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
8a7de711
Commit
8a7de711
authored
Apr 10, 2026
by
Tong Li
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
变邻域+模拟退火+禁忌搜索
parent
932c42d2
Show whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
2120 additions
and
767 deletions
+2120
-767
ScheduleParams.java
src/main/java/com/aps/entity/Algorithm/ScheduleParams.java
+8
-4
GlobalParam.java
src/main/java/com/aps/entity/basic/GlobalParam.java
+4
-4
KpiTargetConfig.java
src/main/java/com/aps/entity/basic/KpiTargetConfig.java
+8
-0
GeneticAlgorithm.java
...main/java/com/aps/service/Algorithm/GeneticAlgorithm.java
+1
-1
GeneticDecoder.java
src/main/java/com/aps/service/Algorithm/GeneticDecoder.java
+9
-10
HillClimbing.java
src/main/java/com/aps/service/Algorithm/HillClimbing.java
+55
-124
HybridAlgorithm.java
src/main/java/com/aps/service/Algorithm/HybridAlgorithm.java
+76
-60
Initialization.java
src/main/java/com/aps/service/Algorithm/Initialization.java
+1
-1
ScheduleOperationService.java
...a/com/aps/service/Algorithm/ScheduleOperationService.java
+1
-1
SimulatedAnnealing.java
...in/java/com/aps/service/Algorithm/SimulatedAnnealing.java
+227
-54
TabuSearch.java
src/main/java/com/aps/service/Algorithm/TabuSearch.java
+277
-11
TabuSearchWithSA.java
...main/java/com/aps/service/Algorithm/TabuSearchWithSA.java
+0
-271
VariableNeighborhoodSearch.java
...com/aps/service/Algorithm/VariableNeighborhoodSearch.java
+1449
-223
SceneService.java
src/main/java/com/aps/service/plan/SceneService.java
+2
-2
PlanResultServiceTest.java
src/test/java/com/aps/demo/PlanResultServiceTest.java
+2
-1
No files found.
src/main/java/com/aps/entity/Algorithm/ScheduleParams.java
View file @
8a7de711
...
...
@@ -15,7 +15,7 @@ public class ScheduleParams {
// 基础参数(自适应调整的基准值)
private
static
final
int
MIN_POPULATION_SIZE
=
10
;
private
static
final
int
MAX_POPULATION_SIZE
=
5
0
;
private
static
final
int
MAX_POPULATION_SIZE
=
2
0
;
private
static
final
int
MIN_MAX_ITERATIONS
=
50
;
private
static
final
int
MAX_MAX_ITERATIONS
=
100
;
private
static
final
float
MIN_CROSSOVER_PROB
=
0.6f
;
...
...
@@ -172,10 +172,14 @@ public class ScheduleParams {
// 1. 种群大小:50 ~ 500,随工序数线性增加
populationSize
=
(
int
)
Math
.
max
(
MIN_POPULATION_SIZE
,
Math
.
min
(
MAX_POPULATION_SIZE
,
MIN_POPULATION_SIZE
+
totalOps
*
populationSizeCoeff
));
int
maxthead
=
Runtime
.
getRuntime
().
availableProcessors
()
-
1
;
populationSize
=
populationSize
/
maxthead
*
maxthead
;
// 确保偶数(方便交叉)
if
(
populationSize
%
2
!=
0
)
{
populationSize
+=
1
;
}
//
if (populationSize % 2 != 0) {
//
populationSize += 1;
//
}
// 2. 最大迭代次数:50 ~ 200,随工序数线性减少
maxIterations
=
(
int
)
Math
.
max
(
MIN_MAX_ITERATIONS
,
...
...
src/main/java/com/aps/entity/basic/GlobalParam.java
View file @
8a7de711
...
...
@@ -73,11 +73,11 @@ public class GlobalParam {
public
GlobalParam
()
{
// 初始化默认目标值配置
//完工时间、总流程时间、总换型时间、机器负载标准差、延迟时间
objectiveConfigs
.
add
(
new
ObjectiveConfig
(
OBJECTIVE_MAKESPAN
,
true
,
1
,
0.
6
));
objectiveConfigs
.
add
(
new
ObjectiveConfig
(
OBJECTIVE_FLOW_TIME
,
fals
e
,
2
,
0.1
));
objectiveConfigs
.
add
(
new
ObjectiveConfig
(
OBJECTIVE_MAKESPAN
,
true
,
1
,
0.
3
));
objectiveConfigs
.
add
(
new
ObjectiveConfig
(
OBJECTIVE_FLOW_TIME
,
tru
e
,
2
,
0.1
));
objectiveConfigs
.
add
(
new
ObjectiveConfig
(
OBJECTIVE_SETUP_TIME
,
true
,
2
,
0.1
));
objectiveConfigs
.
add
(
new
ObjectiveConfig
(
OBJECTIVE_MACHINE_LOAD
,
false
,
3
,
0.1
));
objectiveConfigs
.
add
(
new
ObjectiveConfig
(
OBJECTIVE_TARDINESS
,
true
,
1
,
0.
3
));
objectiveConfigs
.
add
(
new
ObjectiveConfig
(
OBJECTIVE_MACHINE_LOAD
,
true
,
1
,
0.1
));
objectiveConfigs
.
add
(
new
ObjectiveConfig
(
OBJECTIVE_TARDINESS
,
true
,
1
,
0.
6
));
objectiveConfigs
.
sort
(
Comparator
.
comparing
((
ObjectiveConfig
op
)
->
op
.
getLevel
()));
}
...
...
src/main/java/com/aps/entity/basic/KpiTargetConfig.java
0 → 100644
View file @
8a7de711
package
com
.
aps
.
entity
.
basic
;
/**
* 作者:佟礼
* 时间:2026-04-09
*/
public
class
KpiTargetConfig
{
}
src/main/java/com/aps/service/Algorithm/GeneticAlgorithm.java
View file @
8a7de711
...
...
@@ -425,7 +425,7 @@ public class GeneticAlgorithm {
// chromosome.setResultOld(new CopyOnWriteArrayList<>());
// }
decoder
.
decodeChromosomeWithCache
(
chromosome
);
decoder
.
decodeChromosomeWithCache
(
chromosome
,
false
);
if
(
chromosome
.
getFitness
()
==
0
)
{
chromosome
.
setFitness
(
_fitnessCalculator
.
calculateFitness
(
chromosome
,
_objectiveWeights
));
}
...
...
src/main/java/com/aps/service/Algorithm/GeneticDecoder.java
View file @
8a7de711
...
...
@@ -88,17 +88,17 @@ public class GeneticDecoder {
{
FileHelper
.
writeLogFile
(
"解码---------------"
+
population
.
size
()
);
boolean
ismore
=
fals
e
;
boolean
ismore
=
tru
e
;
if
(
ismore
)
{
CompletableFuture
.
allOf
(
population
.
stream
()
.
map
(
chromosome
->
CompletableFuture
.
runAsync
(()
->
decodeChromosomeWithCache
(
chromosome
),
decodeExecutor
))
.
map
(
chromosome
->
CompletableFuture
.
runAsync
(()
->
decodeChromosomeWithCache
(
chromosome
,
false
),
decodeExecutor
))
.
toArray
(
CompletableFuture
[]::
new
))
.
join
();
}
else
{
if
(
population
!=
null
&&
population
.
size
()
>
0
)
{
population
.
forEach
(
chromosome
->
{
decodeChromosomeWithCache
(
chromosome
);
decodeChromosomeWithCache
(
chromosome
,
false
);
});
}
}
...
...
@@ -176,7 +176,7 @@ public class GeneticDecoder {
// return chromosome;
// }
public
Chromosome
decodeChromosomeWithCache
(
Chromosome
chromosome
)
{
public
Chromosome
decodeChromosomeWithCache
(
Chromosome
chromosome
,
boolean
isParallel
)
{
String
cacheKey
=
createCacheKey
(
chromosome
);
// FileHelper.writeLogFile("解码-----------开始-------"+chromosome.getID()+":"+cacheKey );
...
...
@@ -214,7 +214,7 @@ public class GeneticDecoder {
return
chromosome
;
}
// 3. 缓存未命中:执行解码逻辑
decode
(
chromosome
);
decode
(
chromosome
,
isParallel
);
// 4. 将解码结果存入缓存(无锁,ConcurrentHashMap 线程安全)
decodingCache
.
putIfAbsent
(
cacheKey
,
chromosome
);
...
...
@@ -367,12 +367,11 @@ if(finishedOrder==null||finishedOrder.size()==0)
orderProcessCounter
.
put
(
orderid
,
scheduledCount
);
}
public
void
decode
(
Chromosome
chromosome
)
{
int
operationCount
=
chromosome
.
getAllOperations
().
size
();
int
cpuCores
=
Runtime
.
getRuntime
().
availableProcessors
();
public
void
decode
(
Chromosome
chromosome
,
boolean
isParallel
)
{
//
// // 根据工序数量和CPU核心数决定是否使用内部并行
if
(
operationCount
>
5000
&&
cpuCores
>
4
)
{
if
(
isParallel
)
{
// 使用设备并行处理
// FileHelper.writeLogFile("使用并行处理 _s");
parallelDecodeByMachine
(
chromosome
);
...
...
@@ -392,7 +391,7 @@ if(finishedOrder==null||finishedOrder.size()==0)
public
void
serialDecode
(
Chromosome
chromosome
)
{
List
<
OrderMaterialRequirement
>
orderMaterials
=
materialRequirementService
.
buildMultiLevelRequirementNetwork
(
chromosome
,
sceneId
,
baseTime
,
_globalParam
);
//
List<OrderMaterialRequirement> orderMaterials = materialRequirementService.buildMultiLevelRequirementNetwork(chromosome, sceneId, baseTime,_globalParam);
chromosome
.
setScenarioID
(
sceneId
);
if
(
_globalParam
.
isIsCheckSf
())
{
int
isnew
=
generateGlobalOpList
(
chromosome
);
...
...
src/main/java/com/aps/service/Algorithm/HillClimbing.java
View file @
8a7de711
package
com
.
aps
.
service
.
Algorithm
;
import
com.aps.common.util.FileHelper
;
import
com.aps.common.util.GlobalCacheUtil
;
import
com.aps.common.util.ProductionDeepCopyUtil
;
import
com.aps.entity.Algorithm.*
;
import
com.aps.entity.Algorithm.IDAndChildID.GroupResult
;
...
...
@@ -21,6 +22,11 @@ public class HillClimbing {
private
List
<
Entry
>
allOperations
;
private
List
<
Order
>
orders
;
private
List
<
Material
>
materials
;
private
List
<
GroupResult
>
_entryRel
;
//按优先级分组工序
private
Map
<
Double
,
List
<
Entry
>>
priorityGroups
;
...
...
@@ -30,10 +36,17 @@ public class HillClimbing {
// 从List转为Map op.getGroupId() + "_" + op.getSequence(); 做主键
private
Map
<
String
,
Entry
>
entrys
;
public
HillClimbing
(
List
<
Entry
>
allOperations
)
{
private
FitnessCalculator
fitnessCalculator
;
public
HillClimbing
(
List
<
Entry
>
allOperations
,
List
<
Order
>
orders
,
List
<
Material
>
materials
,
List
<
GroupResult
>
entryRel
,
FitnessCalculator
_fitnessCalculator
)
{
this
.
allOperations
=
allOperations
;
this
.
orders
=
orders
;
this
.
materials
=
materials
;
_entryRel
=
entryRel
;
fitnessCalculator
=
_fitnessCalculator
;
// 按优先级分组工序
priorityGroups
=
groupOperationsByPriority
();
...
...
@@ -92,7 +105,7 @@ public class HillClimbing {
Chromosome
machineChange
=
generateMachineChange
(
current
,
op
.
getMachineOptions
(),
maPos
);
if
(
machineChange
!=
null
)
{
decode
(
decoder
,
machineChange
);
decode
(
decoder
,
machineChange
,
machines
);
if
(
isBetter
(
machineChange
,
current
))
{
current
=
machineChange
;
if
(
isBetter
(
current
,
best
))
{
...
...
@@ -263,7 +276,7 @@ public class HillClimbing {
Chromosome
machineChange
=
generateMachineChange
(
current
,
op
.
getMachineOptions
(),
maPos
);
if
(
machineChange
!=
null
)
{
decode
(
decoder
,
machineChange
);
decode
(
decoder
,
machineChange
,
machines
);
if
(
isBetter
(
machineChange
,
current
))
{
current
=
machineChange
;
if
(
isBetter
(
current
,
best
))
{
...
...
@@ -328,7 +341,7 @@ public class HillClimbing {
}
Chromosome
newChromosome
=
swapAtDistance
(
current
,
opPos
,
-
s
*
step
);
decode
(
decoder
,
newChromosome
);
decode
(
decoder
,
newChromosome
,
machines
);
if
(
isBetter
(
newChromosome
,
current
))
{
current
=
newChromosome
;
...
...
@@ -357,7 +370,7 @@ public class HillClimbing {
}
Chromosome
newChromosome
=
swapAtDistance
(
current
,
opPos
,
s
*
step
);
decode
(
decoder
,
newChromosome
);
decode
(
decoder
,
newChromosome
,
machines
);
if
(
isBetter
(
newChromosome
,
current
))
{
current
=
newChromosome
;
...
...
@@ -411,21 +424,24 @@ public class HillClimbing {
}
/**
* 构建位置索引:groupId_sequence -> position
*/
private
Map
<
String
,
Integer
>
buildPositionIndex
(
Chromosome
chromosome
)
{
String
fitness
=
""
;
private
void
writeKpi
(
Chromosome
chromosome
)
{
String
fitness
=
""
;
double
[]
fitness1
=
chromosome
.
getFitnessLevel
();
for
(
int
i
=
0
;
i
<
fitness1
.
length
;
i
++)
{
fitness
+=
fitness1
[
i
]+
","
;
fitness
+=
fitness1
[
i
]
+
","
;
}
FileHelper
.
writeLogFile
(
String
.
format
(
"爬山法 - kpi:%s"
,
fitness
));
}
/**
* 构建位置索引:groupId_sequence -> position
*/
private
Map
<
String
,
Integer
>
buildPositionIndex
(
Chromosome
chromosome
)
{
writeKpi
(
chromosome
);
Map
<
String
,
Integer
>
index
=
new
HashMap
<>();
List
<
Integer
>
os
=
chromosome
.
getOperationSequencing
();
...
...
@@ -546,114 +562,6 @@ public class HillClimbing {
}
return
neighbor
;
}
/**
* 生成邻域解
*/
private
List
<
Chromosome
>
generateNeighbors
(
Chromosome
chromosome
)
{
List
<
Chromosome
>
neighbors
=
new
ArrayList
<>();
// 生成交换邻域
neighbors
.
add
(
generateSwapNeighbor
(
chromosome
));
// 生成反转邻域
neighbors
.
add
(
generateReverseNeighbor
(
chromosome
));
// 生成插入邻域
neighbors
.
add
(
generateInsertNeighbor
(
chromosome
));
// 生成机器选择邻域
neighbors
.
add
(
generateMachineChangeNeighbor
(
chromosome
));
return
neighbors
;
}
/**
* 生成交换邻域解
*/
private
Chromosome
generateSwapNeighbor
(
Chromosome
chromosome
)
{
Chromosome
neighbor
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
List
<
Integer
>
os
=
neighbor
.
getOperationSequencing
();
if
(
os
.
size
()
>=
2
)
{
int
idx1
=
rnd
.
nextInt
(
os
.
size
());
int
idx2
=
rnd
.
nextInt
(
os
.
size
());
while
(
idx2
==
idx1
)
{
idx2
=
rnd
.
nextInt
(
os
.
size
());
}
java
.
util
.
Collections
.
swap
(
os
,
idx1
,
idx2
);
neighbor
.
setOperationSequencing
(
os
);
}
return
neighbor
;
}
/**
* 生成反转邻域解
*/
private
Chromosome
generateReverseNeighbor
(
Chromosome
chromosome
)
{
Chromosome
neighbor
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
List
<
Integer
>
os
=
neighbor
.
getOperationSequencing
();
if
(
os
.
size
()
>=
2
)
{
int
start
=
rnd
.
nextInt
(
os
.
size
());
int
end
=
rnd
.
nextInt
(
os
.
size
());
while
(
end
<=
start
)
{
end
=
rnd
.
nextInt
(
os
.
size
());
}
java
.
util
.
Collections
.
reverse
(
os
.
subList
(
start
,
end
+
1
));
neighbor
.
setOperationSequencing
(
os
);
}
return
neighbor
;
}
/**
* 生成插入邻域解
*/
private
Chromosome
generateInsertNeighbor
(
Chromosome
chromosome
)
{
Chromosome
neighbor
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
List
<
Integer
>
os
=
neighbor
.
getOperationSequencing
();
if
(
os
.
size
()
>=
2
)
{
int
idx1
=
rnd
.
nextInt
(
os
.
size
());
int
idx2
=
rnd
.
nextInt
(
os
.
size
());
while
(
idx2
==
idx1
)
{
idx2
=
rnd
.
nextInt
(
os
.
size
());
}
int
value
=
os
.
remove
(
idx1
);
os
.
add
(
idx2
,
value
);
neighbor
.
setOperationSequencing
(
os
);
}
return
neighbor
;
}
/**
* 生成机器选择邻域解
*/
private
Chromosome
generateMachineChangeNeighbor
(
Chromosome
chromosome
)
{
Chromosome
neighbor
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
List
<
Integer
>
ms
=
neighbor
.
getMachineSelection
();
List
<
GlobalOperationInfo
>
globalOpList
=
chromosome
.
getGlobalOpList
();
if
(!
ms
.
isEmpty
())
{
int
idx
=
rnd
.
nextInt
(
ms
.
size
());
GlobalOperationInfo
globalOp
=
globalOpList
.
get
(
idx
);
Entry
op
=
globalOp
.
getOp
();
if
(
op
.
getMachineOptions
().
size
()
>
1
)
{
int
currentMachineSeq
=
ms
.
get
(
idx
);
List
<
Integer
>
availableMachines
=
new
ArrayList
<>();
for
(
int
i
=
1
;
i
<=
op
.
getMachineOptions
().
size
();
i
++)
{
if
(
i
!=
currentMachineSeq
)
{
availableMachines
.
add
(
i
);
}
}
if
(!
availableMachines
.
isEmpty
())
{
int
newMachineSeq
=
availableMachines
.
get
(
rnd
.
nextInt
(
availableMachines
.
size
()));
ms
.
set
(
idx
,
newMachineSeq
);
neighbor
.
setMachineSelection
(
ms
);
}
}
}
return
neighbor
;
}
/**
* 生成机器选择邻域解
*/
...
...
@@ -703,11 +611,34 @@ public class HillClimbing {
/**
* 解码染色体
*/
private
void
decode
(
GeneticDecoder
decoder
,
Chromosome
chromosome
)
{
// chromosome.setResult(new java.util.concurrent.CopyOnWriteArrayList<>());
decoder
.
decodeChromosomeWithCache
(
chromosome
);
private
void
decode
(
GeneticDecoder
decoder
,
Chromosome
chromosome
,
List
<
Machine
>
machines
)
{
chromosome
.
setResult
(
new
CopyOnWriteArrayList
<>());
// 假设Machine类有拷贝方法,或使用MapStruct等工具进行映射
chromosome
.
setMachines
(
ProductionDeepCopyUtil
.
deepCopyList
(
machines
,
Machine
.
class
));
// 简单拷贝,实际可能需要深拷贝
chromosome
.
setOrders
(
ProductionDeepCopyUtil
.
deepCopyList
(
new
CopyOnWriteArrayList
<>(
orders
),
Order
.
class
)
);
// 简单拷贝,实际可能需要深拷贝
chromosome
.
setOperatRel
(
ProductionDeepCopyUtil
.
deepCopyList
(
new
CopyOnWriteArrayList
<>(
_entryRel
),
GroupResult
.
class
)
);
// 简单拷贝,实际可能需要深拷贝
chromosome
.
setMaterials
(
ProductionDeepCopyUtil
.
deepCopyList
(
materials
,
Material
.
class
));
// 简单拷贝,实际可能需要深拷贝
chromosome
.
setAllOperations
(
ProductionDeepCopyUtil
.
deepCopyList
(
new
CopyOnWriteArrayList
<>(
allOperations
),
Entry
.
class
)
);
// 简单拷贝,实际可能需要深拷贝
//chromosome.setObjectiveWeights(_objectiveWeights);
// chromosome.setBaseTime(param.getBaseTime());
// chromosome.setInitMachines(ProductionDeepCopyUtil.deepCopyList(machines,Machine.class)); // 简单拷贝,实际可能需要深拷贝
// _sceneService.saveChromosomeToFile(chromosome, "12345679");
// 加载锁定工单到ResultOld
List
<
GAScheduleResult
>
lockedOrders
=
GlobalCacheUtil
.
get
(
"locked_orders_"
+
chromosome
.
getScenarioID
());
if
(
lockedOrders
!=
null
&&
!
lockedOrders
.
isEmpty
())
{
chromosome
.
setResultOld
(
ProductionDeepCopyUtil
.
deepCopyList
(
lockedOrders
,
GAScheduleResult
.
class
));
FileHelper
.
writeLogFile
(
"将 "
+
lockedOrders
.
size
()
+
" 个锁定工单加载到初始种群中"
);
}
else
{
chromosome
.
setResultOld
(
new
CopyOnWriteArrayList
<>());
}
decoder
.
decodeChromosomeWithCache
(
chromosome
,
false
);
}
/**
* 比较两个染色体的优劣
...
...
src/main/java/com/aps/service/Algorithm/HybridAlgorithm.java
View file @
8a7de711
package
com
.
aps
.
service
.
Algorithm
;
import
com.aps.common.util.DateTimeUtil
;
import
com.aps.common.util.DeepCopyUtil
;
import
com.aps.common.util.FileHelper
;
import
com.aps.common.util.ProductionDeepCopyUtil
;
import
com.aps.entity.Algorithm.*
;
import
com.aps.common.util.*
;
import
com.aps.entity.Algorithm.*
;
import
com.aps.entity.Algorithm.IDAndChildID.GroupResult
;
import
com.aps.entity.basic.*
;
import
com.aps.service.plan.MachineSchedulerService
;
...
...
@@ -59,7 +56,7 @@ public class HybridAlgorithm {
// 初始化算法实例
private
TabuSearch
_tabuSearch
;
private
TabuSearchWithSA
_tabuSearchWithSA
;
public
HybridAlgorithm
(
GlobalParam
globalParam
,
List
<
Machine
>
machines
,
List
<
Order
>
orders
,
...
...
@@ -109,17 +106,16 @@ int opcount=allOperations.size();
// 预生成全局工序列表(所有初始化方法共享同一顺序)
List
<
GlobalOperationInfo
>
globalOpList
=
initialization
.
generateGlobalOpList
();
// 初始化变邻域搜索
_vns
=
new
VariableNeighborhoodSearch
(
allOperations
,
_fitnessCalculator
);
_hillClimbing
=
new
HillClimbing
(
allOperations
);
_simulatedAnnealing
=
new
SimulatedAnnealing
(
allOperations
,
_fitnessCalculator
);
_tabuSearch
=
new
TabuSearch
(
allOperations
);
_tabuSearchWithSA
=
new
TabuSearchWithSA
(
_GlobalParam
,
allOperations
,
globalOpList
,
_fitnessCalculator
,
_objectiveWeights
);
_vns
=
new
VariableNeighborhoodSearch
(
allOperations
,
orders
,
materials
,
_entryRel
,
_fitnessCalculator
);
_hillClimbing
=
new
HillClimbing
(
allOperations
,
orders
,
materials
,
_entryRel
,
_fitnessCalculator
);
_simulatedAnnealing
=
new
SimulatedAnnealing
(
allOperations
,
orders
,
materials
,
_entryRel
,
_fitnessCalculator
);
_tabuSearch
=
new
TabuSearch
(
allOperations
,
orders
,
materials
,
_entryRel
,
_fitnessCalculator
);
FileHelper
.
writeLogFile
(
"初始化种群-----------开始-------"
);
// 步骤1:使用构造启发式算法生成初始种群
FileHelper
.
writeLogFile
(
"构造启发式初始化-----------开始-------"
);
List
<
Chromosome
>
population
=
initialization
.
generateHeuristicInitialPopulation
(
param
,
globalOpList
);
List
<
Chromosome
>
population
=
initialization
.
generateHeuristicInitialPopulation
(
param
);
FileHelper
.
writeLogFile
(
"构造启发式初始化-----------结束-------"
);
...
...
@@ -137,8 +133,8 @@ int opcount=allOperations.size();
FileHelper
.
writeLogFile
(
"按Objectives去重-----------开始-------"
+
population
.
size
());
population
=
chromosomeDistinctByObjectives
(
population
);
FileHelper
.
writeLogFile
(
"按Objectives去重-----------结束-------"
+
population
.
size
());
// if(1==1)
// return getBestChromosome(population.get(0), param.getBaseTime(), starttime);
// 步骤2:对初始种群进行爬山法局部优化
if
(
opcount
<
20
)
{
...
...
@@ -158,6 +154,8 @@ int opcount=allOperations.size();
GeneticDecoder
vnsDecoder1
=
new
GeneticDecoder
(
_GlobalParam
,
param
.
getBaseTime
(),
machines
,
orders
,
materials
,
machineScheduler
,
materialRequirementService
,
sceneId
);
GeneticDecoder
tabuDecoder1
=
new
GeneticDecoder
(
_GlobalParam
,
param
.
getBaseTime
(),
machines
,
orders
,
materials
,
machineScheduler
,
materialRequirementService
,
sceneId
);
if
(
opcount
<
800
)
{
FileHelper
.
writeLogFile
(
"模拟退火+爬山法优化-----------开始-------"
);
...
...
@@ -166,6 +164,16 @@ int opcount=allOperations.size();
return
getBestChromosome
(
saHcOptimized
,
param
.
getBaseTime
(),
starttime
);
}
if
(
opcount
>=
800
)
{
Chromosome
best
=
population
.
get
(
0
);
best
=
_simulatedAnnealing
.
search
(
best
,
_tabuSearch
,
_vns
,
saDecoder1
,
machines
);
best
=
_vns
.
search
(
best
,
vnsDecoder1
,
machines
);
best
=
_tabuSearch
.
search
(
best
,
_vns
,
tabuDecoder1
,
machines
);
return
getBestChromosome
(
best
,
param
.
getBaseTime
(),
starttime
);
}
...
...
@@ -213,27 +221,35 @@ int opcount=allOperations.size();
List
<
Chromosome
>
newPopulation
=
new
ArrayList
<>();
newPopulation
.
add
(
best
);
int
n
=
0
;
while
(
newPopulation
.
size
()
<
param
.
getPopulationSize
())
{
// 选择父代
FileHelper
.
writeLogFile
(
"交叉-----------开始-------"
+
n
);
Chromosome
parent1
=
selected
.
get
(
rnd
.
nextInt
(
selected
.
size
()));
Chromosome
parent2
=
selected
.
get
(
rnd
.
nextInt
(
selected
.
size
()));
// 交叉
Chromosome
child
=
parent1
;
if
(
rnd
.
nextDouble
()
<
param
.
getCrossoverProb
())
{
// 假设PoxCrossover返回包含两个子染色体的数组
Pair
<
Chromosome
,
Chromosome
>
children
=
geneticOps
.
poxCrossover
(
parent1
,
parent2
,
ordercount
);
child
=
children
.
getFirst
();
child
.
setID
(
UUID
.
randomUUID
().
toString
());
}
// 变异
if
(
rnd
.
nextDouble
()
<
param
.
getMutationProb
())
{
geneticOps
.
mutate
(
child
,
globalOpList
);
}
// if (rnd.nextDouble() < param.getCrossoverProb()) {
// // 假设PoxCrossover返回包含两个子染色体的数组
// Pair<Chromosome, Chromosome> children = geneticOps.poxCrossover(parent1, parent2, ordercount);
// child=children.getFirst();
// initDataToChromosome(child,param, allOperations,globalOpList);
// child.setID(UUID.randomUUID().toString());
// }
// // 变异
// if (rnd.nextDouble() < param.getMutationProb()) {
// geneticOps.mutate(child, globalOpList);
// }
// 核心融合链(工业级标准顺序:GA生成子代 → SA跳坑 → VNS扩邻域 → TS精优化)
child
=
_simulatedAnnealing
.
search
(
child
,
_tabuSearch
,
_vns
,
saDecoder1
,
machines
);
child
=
_vns
.
search
(
child
,
vnsDecoder1
,
machines
);
child
=
_tabuSearch
.
search
(
child
,
_vns
,
tabuDecoder1
,
machines
);
newPopulation
.
add
(
child
);
FileHelper
.
writeLogFile
(
"交叉-----------结束-------"
+
n
);
}
population
=
chromosomeDistinctByObjectives
(
newPopulation
);;
...
...
@@ -291,18 +307,7 @@ int opcount=allOperations.size();
return
best
;
}
private
Chromosome
GetBest
(
List
<
List
<
Chromosome
>>
fronts
,
String
msg
)
{
// WriteKpis(fronts,msg);
List
<
Chromosome
>
fChromosomes
=
fronts
.
get
(
0
);
fChromosomes
.
sort
((
c1
,
c2
)
->
{
int
rankCompare
=
Double
.
compare
(
c1
.
getCrowdingDistance
(),
c2
.
getCrowdingDistance
());
return
rankCompare
!=
0
?
rankCompare
:
Double
.
compare
(
c1
.
getFitness
(),
c2
.
getFitness
());
});
Chromosome
best
=
fChromosomes
.
get
(
0
);
// WriteKpi(best,"最大");
return
best
;
}
private
List
<
Chromosome
>
chromosomeDistinct
(
List
<
Chromosome
>
population
)
{
if
(
population
==
null
)
...
...
@@ -380,31 +385,8 @@ int opcount=allOperations.size();
return
false
;
}
private
List
<
Chromosome
>
chromosomeDistinct1
(
List
<
Chromosome
>
population
)
{
if
(
population
==
null
)
{
FileHelper
.
writeLogFile
(
String
.
format
(
"排产-----------方案数量---%d-------"
,
0
));
return
population
;
}
// List<Chromosome> population1 = population.stream().filter(t->t.getGeneStr()==null).collect(Collectors.toList());
population
=
population
.
stream
()
.
collect
(
Collectors
.
toMap
(
Chromosome:
:
getGeneStr
,
// key:去重的字段(GeneStr)
u
->
u
,
// value:Chromosome对象
(
u1
,
u2
)
->
u1
.
getFitness
()
>
u2
.
getFitness
()
?
u1
:
u2
// 重复时保留第一个元素
))
.
values
()
// 获取去重后的
.
stream
()
.
collect
(
Collectors
.
toList
());
return
population
;
}
private
void
WriteKpis
(
List
<
List
<
Chromosome
>>
fronts
,
String
index
)
{
for
(
int
i
=
0
;
i
<
fronts
.
size
();
i
++)
{
...
...
@@ -433,6 +415,40 @@ int opcount=allOperations.size();
new
ThreadPoolExecutor
.
CallerRunsPolicy
()
// 任务满了主线程执行,不丢失任务
);
private
void
initDataToChromosome
(
Chromosome
chromosome
,
ScheduleParams
param
,
List
<
Entry
>
allOperations
,
List
<
GlobalOperationInfo
>
globalOpList
)
{
if
(
chromosome
==
null
){
System
.
out
.
println
(
"chromosome==null"
);
return
;
}
chromosome
.
setResult
(
new
CopyOnWriteArrayList
<>());
// 假设Machine类有拷贝方法,或使用MapStruct等工具进行映射
chromosome
.
setMachines
(
ProductionDeepCopyUtil
.
deepCopyList
(
machines
,
Machine
.
class
));
// 简单拷贝,实际可能需要深拷贝
chromosome
.
setOrders
(
ProductionDeepCopyUtil
.
deepCopyList
(
new
CopyOnWriteArrayList
<>(
orders
),
Order
.
class
)
);
// 简单拷贝,实际可能需要深拷贝
chromosome
.
setOperatRel
(
ProductionDeepCopyUtil
.
deepCopyList
(
new
CopyOnWriteArrayList
<>(
_entryRel
),
GroupResult
.
class
)
);
// 简单拷贝,实际可能需要深拷贝
chromosome
.
setMaterials
(
ProductionDeepCopyUtil
.
deepCopyList
(
materials
,
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
());
// chromosome.setInitMachines(ProductionDeepCopyUtil.deepCopyList(machines,Machine.class)); // 简单拷贝,实际可能需要深拷贝
// _sceneService.saveChromosomeToFile(chromosome, "12345679");
// 加载锁定工单到ResultOld
List
<
GAScheduleResult
>
lockedOrders
=
GlobalCacheUtil
.
get
(
"locked_orders_"
+
sceneId
);
if
(
lockedOrders
!=
null
&&
!
lockedOrders
.
isEmpty
())
{
chromosome
.
setResultOld
(
ProductionDeepCopyUtil
.
deepCopyList
(
lockedOrders
,
GAScheduleResult
.
class
));
FileHelper
.
writeLogFile
(
"将 "
+
lockedOrders
.
size
()
+
" 个锁定工单加载到初始种群中"
);
}
else
{
chromosome
.
setResultOld
(
new
CopyOnWriteArrayList
<>());
}
}
private
void
Chromosomedecode
(
ScheduleParams
param
,
List
<
Entry
>
allOperations
,
List
<
GlobalOperationInfo
>
globalOpList
,
List
<
Chromosome
>
population
)
{
FileHelper
.
writeLogFile
(
"解码---------------"
+
population
.
size
()
);
...
...
@@ -479,7 +495,7 @@ int opcount=allOperations.size();
// chromosome.setInitMachines(ProductionDeepCopyUtil.deepCopyList(machines,Machine.class)); // 简单拷贝,实际可能需要深拷贝
// _sceneService.saveChromosomeToFile(chromosome, "12345679");
decoder
.
decodeChromosomeWithCache
(
chromosome
);
decoder
.
decodeChromosomeWithCache
(
chromosome
,
false
);
// if (chromosome.getFitness() == 0) {
// chromosome.setFitness(_fitnessCalculator.calculateFitness(chromosome, _objectiveWeights));
// }
...
...
src/main/java/com/aps/service/Algorithm/Initialization.java
View file @
8a7de711
...
...
@@ -343,7 +343,7 @@ chromo.setOrders(new CopyOnWriteArrayList<>(orders));
/**
* 使用构造启发式算法生成初始种群
*/
public
List
<
Chromosome
>
generateHeuristicInitialPopulation
(
ScheduleParams
param
,
List
<
GlobalOperationInfo
>
globalOpList
)
{
public
List
<
Chromosome
>
generateHeuristicInitialPopulation
(
ScheduleParams
param
)
{
List
<
Chromosome
>
population
=
new
ArrayList
<>();
int
populationSize
=
param
.
getPopulationSize
();
this
.
baseTime
=
param
.
getBaseTime
();
...
...
src/main/java/com/aps/service/Algorithm/ScheduleOperationService.java
View file @
8a7de711
...
...
@@ -1885,7 +1885,7 @@ if(targetOp.getSequence()>1) {
decoder
.
decode
(
chromosome
);
decoder
.
decode
(
chromosome
,
false
);
KpiCalculator
kpiCalculator
=
new
KpiCalculator
(
chromosome
);
kpiCalculator
.
calculatekpi
();
...
...
src/main/java/com/aps/service/Algorithm/SimulatedAnnealing.java
View file @
8a7de711
package
com
.
aps
.
service
.
Algorithm
;
import
com.aps.common.util.FileHelper
;
import
com.aps.common.util.GlobalCacheUtil
;
import
com.aps.common.util.ProductionDeepCopyUtil
;
import
com.aps.entity.Algorithm.*
;
import
com.aps.entity.basic.Entry
;
import
com.aps.entity.basic.GlobalParam
;
import
com.aps.entity.basic.Machine
;
import
com.aps.entity.basic.MachineOption
;
import
com.aps.entity.Algorithm.IDAndChildID.GroupResult
;
import
com.aps.entity.basic.*
;
import
java.util.*
;
import
java.util.concurrent.*
;
...
...
@@ -18,19 +17,39 @@ import java.util.stream.Collectors;
public
class
SimulatedAnnealing
{
private
final
Random
rnd
=
new
Random
();
private
void
log
(
String
message
)
{
log
(
message
,
false
);
}
private
void
log
(
String
message
,
boolean
enableLogging
)
{
if
(
enableLogging
)
{
FileHelper
.
writeLogFile
(
message
);
}
}
private
List
<
Entry
>
allOperations
;
private
List
<
Order
>
orders
;
private
List
<
Material
>
materials
;
private
List
<
GroupResult
>
_entryRel
;
private
FitnessCalculator
fitnessCalculator
;
private
Map
<
String
,
Entry
>
entrys
;
private
Map
<
String
,
Entry
>
entrys
;
private
Map
<
Integer
,
Entry
>
entrybyids
;
public
SimulatedAnnealing
(
List
<
Entry
>
allOperations
,
FitnessCalculator
fitnessCalculator
)
{
public
SimulatedAnnealing
(
List
<
Entry
>
allOperations
,
List
<
Order
>
orders
,
List
<
Material
>
materials
,
List
<
GroupResult
>
entryRel
,
FitnessCalculator
_fitnessCalculator
)
{
this
.
allOperations
=
allOperations
;
this
.
orders
=
orders
;
this
.
materials
=
materials
;
_entryRel
=
entryRel
;
Map
<
Integer
,
Object
>
mp
=
buildEntryKey
();
this
.
fitnessCalculator
=
fitnessCalculator
;
this
.
fitnessCalculator
=
_
fitnessCalculator
;
entrys
=(
Map
<
String
,
Entry
>)
mp
.
get
(
1
);
entrybyids
=(
Map
<
Integer
,
Entry
>)
mp
.
get
(
2
);
...
...
@@ -75,16 +94,17 @@ private Map<String, Entry> entrys;
* 流程:模拟退火全局探索(按概率接受劣解)→ 降温 → 温度低时爬山法局部求精 → 输出最优
*/
public
Chromosome
searchWithHillClimbing
(
Chromosome
chromosome
,
VariableNeighborhoodSearch
vns
,
GeneticDecoder
decoder
,
List
<
Machine
>
machines
)
{
FileHelper
.
writeLogFile
(
"模拟退火+爬山法 - 开始执行"
);
log
(
"模拟退火+爬山法 - 开始执行"
,
true
);
Chromosome
current
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
Chromosome
best
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
writeKpi
(
best
);
// 初始化解码
// 记录初始KPI用于计算改进率
double
[]
initialFitnessLevel
=
best
.
getFitnessLevel
().
clone
();
double
initialFitness
=
best
.
getFitness
();
// FileHelper.writeLogFile
("模拟退火+爬山法 - 初始化解码完成");
// log
("模拟退火+爬山法 - 初始化解码完成");
// 初始化温度
double
temperature
=
100.0
;
...
...
@@ -92,15 +112,22 @@ private Map<String, Entry> entrys;
double
temperatureThreshold
=
1.0
;
int
maxIterations
=
300
;
int
noImproveCount
=
0
;
int
maxNoImprove
=
50
;
int
maxNoImprove
=
30
;
// 降低最大无改进次数
FileHelper
.
writeLogFile
(
String
.
format
(
"模拟退火+爬山法 - 参数配置:温度=%.1f, 降温率=%.2f, 阈值=%.1f, 最大迭代=%d"
,
temperature
,
coolingRate
,
temperatureThreshold
,
maxIterations
));
// 新增:改进率监控参数
int
stagnantWindow
=
15
;
// 观察窗口大小
int
[]
recentImprovements
=
new
int
[
stagnantWindow
];
// 记录最近窗口内的改进情况
double
improvementRateThreshold
=
0.05
;
// 改进率阈值(5%)
log
(
String
.
format
(
"模拟退火+爬山法 - 参数配置:温度=%.1f, 降温率=%.2f, 阈值=%.1f, 最大迭代=%d, 最大无改进=%d"
,
temperature
,
coolingRate
,
temperatureThreshold
,
maxIterations
,
maxNoImprove
));
int
acceptCount
=
0
;
int
improveCount
=
0
;
int
totalIterations
=
0
;
for
(
int
i
=
0
;
i
<
maxIterations
;
i
++)
{
totalIterations
=
i
+
1
;
boolean
improved
=
false
;
// 1. 使用智能策略生成邻域解(找瓶颈工序/设备)
...
...
@@ -120,46 +147,74 @@ private Map<String, Entry> entrys;
acceptCount
++;
// 更新全局最优
if
(
isBetter
(
current
,
best
))
{
best
=
ProductionDeepCopyUtil
.
deepCopy
(
current
,
Chromosome
.
class
);
writeKpi
(
best
);
improved
=
true
;
improveCount
++;
noImproveCount
=
0
;
FileHelper
.
writeLogFile
(
String
.
format
(
"模拟退火+爬山法 - 迭代%d:找到更优解,fitness=%.4f"
,
i
,
best
.
getFitness
()));
// 记录改进详情
logImprovementDetails
(
best
,
initialFitnessLevel
,
initialFitness
,
totalIterations
);
log
(
String
.
format
(
"模拟退火+爬山法 - 迭代%d:找到更优解,fitness=%.4f"
,
totalIterations
,
best
.
getFitness
()),
true
);
}
}
if
(!
improved
)
{
noImproveCount
++;
}
// 记录本次改进情况
if
(
totalIterations
<=
stagnantWindow
)
{
recentImprovements
[
totalIterations
-
1
]
=
improved
?
1
:
0
;
}
// 5. 降温
temperature
*=
coolingRate
;
// 每50次迭代输出一次状态
if
((
i
+
1
)
%
50
==
0
)
{
FileHelper
.
writeLogFile
(
String
.
format
(
"模拟退火+爬山法 - 迭代%d/%d:温度=%.4f, 接受数=%d, 改进数=%d, 无改进连续=%d"
,
i
+
1
,
maxIterations
,
temperature
,
acceptCount
,
improveCount
,
noImproveCount
));
// 每30次迭代输出一次状态
if
((
totalIterations
)
%
30
==
0
)
{
log
(
String
.
format
(
"模拟退火+爬山法 - 迭代%d/%d:温度=%.4f, 接受数=%d, 改进数=%d, 无改进连续=%d, 总改进率=%.2f%%"
,
totalIterations
,
maxIterations
,
temperature
,
acceptCount
,
improveCount
,
noImproveCount
,
totalIterations
>
0
?
(
double
)
improveCount
/
totalIterations
*
100
:
0
));
}
// 6. 提前停止条件:温度低于阈值 或 连续多次没改进
if
(
temperature
<
temperatureThreshold
||
noImproveCount
>=
maxNoImprove
)
{
String
stopReason
=
temperature
<
temperatureThreshold
?
"温度低于阈值"
:
"连续无改进达到上限"
;
FileHelper
.
writeLogFile
(
String
.
format
(
"模拟退火+爬山法 - 提前停止:%s,迭代%d次,最终温度=%.4f"
,
stopReason
,
i
+
1
,
temperature
));
// 6. 提前停止条件
boolean
shouldStop
=
false
;
String
stopReason
=
""
;
FileHelper
.
writeLogFile
(
"模拟退火+爬山法 - 切换到爬山法求精"
);
HillClimbing
hillClimbing
=
new
HillClimbing
(
allOperations
);
if
(
temperature
<
temperatureThreshold
)
{
shouldStop
=
true
;
stopReason
=
"温度低于阈值"
;
}
else
if
(
noImproveCount
>=
maxNoImprove
)
{
shouldStop
=
true
;
stopReason
=
String
.
format
(
"连续无改进达到上限(%d次)"
,
maxNoImprove
);
}
else
if
(
totalIterations
>=
stagnantWindow
)
{
// 检查改进率是否过低
double
recentImproveRate
=
calculateRecentImprovementRate
(
recentImprovements
,
stagnantWindow
);
if
(
recentImproveRate
<
improvementRateThreshold
)
{
shouldStop
=
true
;
stopReason
=
String
.
format
(
"最近%d次迭代改进率过低(%.2f%%)"
,
stagnantWindow
,
recentImproveRate
*
100
);
}
}
if
(
shouldStop
)
{
log
(
String
.
format
(
"模拟退火+爬山法 - 提前停止:%s,迭代%d次,最终温度=%.4f"
,
stopReason
,
totalIterations
,
temperature
));
logFinalSummary
(
best
,
initialFitnessLevel
,
initialFitness
,
improveCount
,
totalIterations
);
log
(
"模拟退火+爬山法 - 切换到爬山法求精"
);
HillClimbing
hillClimbing
=
new
HillClimbing
(
allOperations
,
orders
,
materials
,
_entryRel
,
fitnessCalculator
);
Chromosome
refined
=
hillClimbing
.
search
(
best
,
decoder
,
machines
);
FileHelper
.
writeLogFile
(
"模拟退火+爬山法 - 爬山法求精完成"
);
log
(
"模拟退火+爬山法 - 爬山法求精完成"
);
return
refined
;
}
}
FileHelper
.
writeLogFile
(
String
.
format
(
"模拟退火+爬山法 - 完成所有%d次迭代,最终fitness=%.4f"
,
maxIterations
,
best
.
getFitness
()));
log
(
String
.
format
(
"模拟退火+爬山法 - 完成所有%d次迭代,最终fitness=%.4f"
,
maxIterations
,
best
.
getFitness
()),
true
);
logFinalSummary
(
best
,
initialFitnessLevel
,
initialFitness
,
improveCount
,
totalIterations
);
// 7. 输出全局最优排产
return
best
;
...
...
@@ -170,7 +225,7 @@ private Map<String, Entry> entrys;
* 流程:模拟退火全局探索(按概率接受劣解)→ 降温 → 输出最优
*/
public
Chromosome
search
(
Chromosome
chromosome
,
TabuSearch
tabusearch
,
VariableNeighborhoodSearch
vns
,
GeneticDecoder
decoder
,
List
<
Machine
>
machines
)
{
FileHelper
.
writeLogFile
(
"模拟退火+爬山法 - 开始执行"
);
log
(
"模拟退火 - 开始执行"
,
true
);
Chromosome
current
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
decode
(
decoder
,
current
,
machines
);
...
...
@@ -178,9 +233,11 @@ private Map<String, Entry> entrys;
writeKpi
(
best
);
// 初始化解码
// 记录初始KPI用于计算改进率
double
[]
initialFitnessLevel
=
best
.
getFitnessLevel
().
clone
();
double
initialFitness
=
best
.
getFitness
();
// FileHelper.writeLogFile("模拟退火+爬山法 - 初始化解码完成");
// log("模拟退火+爬山法 - 初始化解码完成");
// 初始化温度
double
temperature
=
100.0
;
...
...
@@ -188,16 +245,24 @@ private Map<String, Entry> entrys;
double
temperatureThreshold
=
1.0
;
int
maxIterations
=
300
;
int
noImproveCount
=
0
;
int
maxNoImprove
=
50
;
int
maxNoImprove
=
20
;
// 降低最大无改进次数,更快提前结束
// 新增:改进率监控参数
int
stagnantWindow
=
10
;
// 观察窗口大小
int
[]
recentImprovements
=
new
int
[
stagnantWindow
];
// 记录最近窗口内的改进情况
double
improvementRateThreshold
=
0.001
;
// 改进率阈值
FileHelper
.
writeLogFile
(
String
.
format
(
"模拟退火+爬山法 - 参数配置:温度=%.1f, 降温率=%.2f, 阈值=%.1f, 最大迭代
=%d"
,
temperature
,
coolingRate
,
temperatureThreshold
,
maxIterations
));
log
(
String
.
format
(
"模拟退火 - 参数配置:温度=%.1f, 降温率=%.2f, 阈值=%.1f, 最大迭代=%d, 最大无改进
=%d"
,
temperature
,
coolingRate
,
temperatureThreshold
,
maxIterations
,
maxNoImprove
));
int
acceptCount
=
0
;
int
improveCount
=
0
;
int
totalIterations
=
0
;
for
(
int
i
=
0
;
i
<
maxIterations
;
i
++)
{
totalIterations
=
i
+
1
;
boolean
improved
=
false
;
log
(
String
.
format
(
"模拟退火 - 迭代%d:"
,
totalIterations
));
// 1. 使用智能策略生成邻域解(找瓶颈工序/设备)
Chromosome
neighbor
=
vns
.
generateNeighbor
(
current
);
...
...
@@ -206,6 +271,11 @@ private Map<String, Entry> entrys;
// 跳过禁忌解(除非是最优解)
if
(
tabusearch
.
isTabu
(
neighbor
.
getGeneStr
())
&&
!
isBetter
(
current
,
best
))
{
temperature
*=
coolingRate
;
noImproveCount
++;
// 记录本次无改进
if
(
totalIterations
<=
stagnantWindow
)
{
recentImprovements
[
totalIterations
-
1
]
=
0
;
}
continue
;
}
...
...
@@ -216,42 +286,124 @@ private Map<String, Entry> entrys;
boolean
accepted
=
false
;
if
(
energyDifference
>
0
||
rnd
.
nextDouble
()
<
Math
.
exp
(
energyDifference
/
temperature
))
{
current
=
neighbor
;
accepted
=
true
;
acceptCount
++;
acceptCount
++;
if
(
isBetter
(
current
,
best
))
{
best
=
ProductionDeepCopyUtil
.
deepCopy
(
current
,
Chromosome
.
class
);
tabusearch
.
addToTabuList
(
best
.
getGeneStr
());
writeKpi
(
best
);
improved
=
true
;
improveCount
++;
noImproveCount
=
0
;
FileHelper
.
writeLogFile
(
String
.
format
(
"模拟退火+爬山法 - 迭代%d:找到更优解,fitness=%.4f"
,
i
,
best
.
getFitness
()));
// 记录改进详情
logImprovementDetails
(
best
,
initialFitnessLevel
,
initialFitness
,
totalIterations
);
log
(
String
.
format
(
"模拟退火 - 迭代%d:找到更优解,fitness=%.4f"
,
totalIterations
,
best
.
getFitness
()));
}
}
if
(!
improved
)
{
noImproveCount
++;
}
// 记录本次改进情况
if
(
totalIterations
<=
stagnantWindow
)
{
recentImprovements
[
totalIterations
-
1
]
=
improved
?
1
:
0
;
}
// 5. 降温
temperature
*=
coolingRate
;
// 每50次迭代输出一次状态
if
((
i
+
1
)
%
50
==
0
)
{
FileHelper
.
writeLogFile
(
String
.
format
(
"模拟退火+爬山法 - 迭代%d/%d:温度=%.4f, 接受数=%d, 改进数=%d, 无改进连续=%d"
,
i
+
1
,
maxIterations
,
temperature
,
acceptCount
,
improveCount
,
noImproveCount
));
// 每次迭代都输出状态
log
(
String
.
format
(
"模拟退火 - 迭代%d/%d:温度=%.4f, 接受数=%d, 改进数=%d, 无改进连续=%d, 总改进率=%.2f%%"
,
totalIterations
,
maxIterations
,
temperature
,
acceptCount
,
improveCount
,
noImproveCount
,
totalIterations
>
0
?
(
double
)
improveCount
/
totalIterations
*
100
:
0
));
// 6. 检查提前停止条件
boolean
shouldStop
=
false
;
String
stopReason
=
""
;
if
(
temperature
<
temperatureThreshold
)
{
shouldStop
=
true
;
stopReason
=
"温度低于阈值"
;
}
else
if
(
noImproveCount
>=
maxNoImprove
)
{
shouldStop
=
true
;
stopReason
=
String
.
format
(
"连续无改进达到上限(%d次)"
,
maxNoImprove
);
}
else
if
(
totalIterations
>=
stagnantWindow
)
{
// 检查改进率是否过低
double
recentImproveRate
=
calculateRecentImprovementRate
(
recentImprovements
,
stagnantWindow
);
if
(
recentImproveRate
<
improvementRateThreshold
)
{
shouldStop
=
true
;
stopReason
=
String
.
format
(
"最近%d次迭代改进率过低(%.2f%%)"
,
stagnantWindow
,
recentImproveRate
*
100
);
}
}
if
(
shouldStop
)
{
log
(
String
.
format
(
"模拟退火 - 提前停止:%s,迭代%d次,最终温度=%.4f"
,
stopReason
,
totalIterations
,
temperature
));
logFinalSummary
(
best
,
initialFitnessLevel
,
initialFitness
,
improveCount
,
totalIterations
);
return
best
;
}
}
FileHelper
.
writeLogFile
(
String
.
format
(
"模拟退火+爬山法 - 完成所有%d次迭代,最终fitness=%.4f"
,
maxIterations
,
best
.
getFitness
()));
log
(
String
.
format
(
"模拟退火 - 完成所有%d次迭代,最终fitness=%.4f"
,
maxIterations
,
best
.
getFitness
()),
true
);
logFinalSummary
(
best
,
initialFitnessLevel
,
initialFitness
,
improveCount
,
totalIterations
);
// 7. 输出全局最优排产
return
best
;
}
/**
* 记录改进详情
*/
private
void
logImprovementDetails
(
Chromosome
best
,
double
[]
initialFitnessLevel
,
double
initialFitness
,
int
iteration
)
{
StringBuilder
sb
=
new
StringBuilder
(
"模拟退火 - 改进详情: 迭代"
+
iteration
+
", "
);
double
[]
currentFitness
=
best
.
getFitnessLevel
();
for
(
int
i
=
0
;
i
<
currentFitness
.
length
;
i
++)
{
double
improvement
=
currentFitness
[
i
]
-
initialFitnessLevel
[
i
];
sb
.
append
(
String
.
format
(
"KPI%d: %.4f→%.4f(+%.4f) "
,
i
+
1
,
initialFitnessLevel
[
i
],
currentFitness
[
i
],
improvement
));
}
double
totalImprovement
=
best
.
getFitness
()
-
initialFitness
;
sb
.
append
(
String
.
format
(
"总Fitness: %.4f→%.4f(+%.4f)"
,
initialFitness
,
best
.
getFitness
(),
totalImprovement
));
log
(
sb
.
toString
());
}
/**
* 计算最近改进率
*/
private
double
calculateRecentImprovementRate
(
int
[]
recentImprovements
,
int
windowSize
)
{
int
improveCount
=
0
;
for
(
int
i
=
0
;
i
<
windowSize
;
i
++)
{
improveCount
+=
recentImprovements
[
i
];
}
return
(
double
)
improveCount
/
windowSize
;
}
/**
* 记录最终总结
*/
private
void
logFinalSummary
(
Chromosome
best
,
double
[]
initialFitnessLevel
,
double
initialFitness
,
int
improveCount
,
int
totalIterations
)
{
StringBuilder
sb
=
new
StringBuilder
(
"模拟退火 - 最终总结: "
);
double
[]
currentFitness
=
best
.
getFitnessLevel
();
sb
.
append
(
String
.
format
(
"总迭代%d次, 成功改进%d次, 改进率%.2f%%. "
,
totalIterations
,
improveCount
,
totalIterations
>
0
?
(
double
)
improveCount
/
totalIterations
*
100
:
0
));
for
(
int
i
=
0
;
i
<
currentFitness
.
length
;
i
++)
{
double
improvement
=
currentFitness
[
i
]
-
initialFitnessLevel
[
i
];
sb
.
append
(
String
.
format
(
"KPI%d: %.4f→%.4f(%.2f%%) "
,
i
+
1
,
initialFitnessLevel
[
i
],
currentFitness
[
i
],
initialFitnessLevel
[
i
]
>
0
?
improvement
/
initialFitnessLevel
[
i
]
*
100
:
0
));
}
double
totalImprovement
=
best
.
getFitness
()
-
initialFitness
;
sb
.
append
(
String
.
format
(
"总Fitness: %.4f→%.4f(%.2f%%)"
,
initialFitness
,
best
.
getFitness
(),
initialFitness
>
0
?
totalImprovement
/
initialFitness
*
100
:
0
));
log
(
sb
.
toString
());
}
private
void
writeKpi
(
Chromosome
chromosome
)
{
String
fitness
=
""
;
...
...
@@ -261,7 +413,7 @@ private Map<String, Entry> entrys;
fitness
+=
fitness1
[
i
]
+
","
;
}
FileHelper
.
writeLogFile
(
String
.
format
(
"爬山法 - kpi:%s"
,
fitness
)
);
log
(
String
.
format
(
"模拟退火 - kpi:%s"
,
fitness
),
true
);
}
...
...
@@ -333,6 +485,9 @@ private Map<String, Entry> entrys;
return
index0
;
}
/**
* 解码染色体
*/
/**
* 解码染色体
*/
...
...
@@ -341,11 +496,29 @@ private Map<String, Entry> entrys;
// 假设Machine类有拷贝方法,或使用MapStruct等工具进行映射
chromosome
.
setMachines
(
ProductionDeepCopyUtil
.
deepCopyList
(
machines
,
Machine
.
class
));
// 简单拷贝,实际可能需要深拷贝
chromosome
.
setMachines
(
ProductionDeepCopyUtil
.
deepCopyList
(
machines
,
Machine
.
class
));
// 简单拷贝,实际可能需要深拷贝
chromosome
.
setOrders
(
ProductionDeepCopyUtil
.
deepCopyList
(
new
CopyOnWriteArrayList
<>(
orders
),
Order
.
class
)
);
// 简单拷贝,实际可能需要深拷贝
chromosome
.
setOperatRel
(
ProductionDeepCopyUtil
.
deepCopyList
(
new
CopyOnWriteArrayList
<>(
_entryRel
),
GroupResult
.
class
)
);
// 简单拷贝,实际可能需要深拷贝
chromosome
.
setMaterials
(
ProductionDeepCopyUtil
.
deepCopyList
(
materials
,
Material
.
class
));
// 简单拷贝,实际可能需要深拷贝
decoder
.
decodeChromosomeWithCache
(
chromosome
);
chromosome
.
setAllOperations
(
ProductionDeepCopyUtil
.
deepCopyList
(
new
CopyOnWriteArrayList
<>(
allOperations
),
Entry
.
class
)
);
// 简单拷贝,实际可能需要深拷贝
//chromosome.setObjectiveWeights(_objectiveWeights);
// chromosome.setBaseTime(param.getBaseTime());
// chromosome.setInitMachines(ProductionDeepCopyUtil.deepCopyList(machines,Machine.class)); // 简单拷贝,实际可能需要深拷贝
// _sceneService.saveChromosomeToFile(chromosome, "12345679");
// 加载锁定工单到ResultOld
List
<
GAScheduleResult
>
lockedOrders
=
GlobalCacheUtil
.
get
(
"locked_orders_"
+
chromosome
.
getScenarioID
());
if
(
lockedOrders
!=
null
&&
!
lockedOrders
.
isEmpty
())
{
chromosome
.
setResultOld
(
ProductionDeepCopyUtil
.
deepCopyList
(
lockedOrders
,
GAScheduleResult
.
class
));
log
(
"将 "
+
lockedOrders
.
size
()
+
" 个锁定工单加载到初始种群中"
);
}
else
{
chromosome
.
setResultOld
(
new
CopyOnWriteArrayList
<>());
}
decoder
.
decodeChromosomeWithCache
(
chromosome
,
true
);
}
/**
* 比较两个染色体的优劣(基于fitnessLevel多层次比较)
...
...
src/main/java/com/aps/service/Algorithm/TabuSearch.java
View file @
8a7de711
package
com
.
aps
.
service
.
Algorithm
;
import
com.aps.common.util.FileHelper
;
import
com.aps.common.util.GlobalCacheUtil
;
import
com.aps.common.util.ProductionDeepCopyUtil
;
import
com.aps.entity.Algorithm.*
;
import
com.aps.entity.
basic.Entry
;
import
com.aps.entity.basic.
GlobalParam
;
import
com.aps.entity.
Algorithm.IDAndChildID.GroupResult
;
import
com.aps.entity.basic.
*
;
import
java.util.*
;
import
java.util.concurrent.CopyOnWriteArrayList
;
/**
* 禁忌搜索算法
*/
public
class
TabuSearch
{
private
List
<
Entry
>
allOperations
;
private
void
log
(
String
message
)
{
log
(
message
,
false
);
}
private
void
log
(
String
message
,
boolean
enableLogging
)
{
if
(
enableLogging
)
{
FileHelper
.
writeLogFile
(
message
);
}
}
private
FitnessCalculator
fitnessCalculator
;
// 禁忌表
private
List
<
String
>
tabuList
;
private
int
tabuListSize
=
50
;
public
TabuSearch
(
List
<
Entry
>
allOperations
)
{
private
List
<
Machine
>
cachedMachines
;
private
List
<
Order
>
cachedOrders
;
private
List
<
GroupResult
>
cachedEntryRel
;
private
List
<
Material
>
cachedMaterials
;
private
List
<
Entry
>
cachedAllOperations
;
// 渴望准则:记录最优解的 fitness
private
double
[]
bestFitness
;
public
TabuSearch
(
List
<
Entry
>
allOperations
,
List
<
Order
>
orders
,
List
<
Material
>
materials
,
List
<
GroupResult
>
entryRel
,
FitnessCalculator
_fitnessCalculator
)
{
this
.
tabuList
=
new
ArrayList
<>();
// 工序越多,禁忌表越长(适配1000+工序)
this
.
tabuListSize
=
Math
.
min
(
50
,
allOperations
.
size
()
/
30
);
fitnessCalculator
=
_fitnessCalculator
;
// 预缓存解码需要的深拷贝列表,避免重复拷贝
cachedAllOperations
=
ProductionDeepCopyUtil
.
deepCopyList
(
new
CopyOnWriteArrayList
<>(
allOperations
),
Entry
.
class
);
cachedOrders
=
ProductionDeepCopyUtil
.
deepCopyList
(
new
CopyOnWriteArrayList
<>(
orders
),
Order
.
class
);
cachedEntryRel
=
ProductionDeepCopyUtil
.
deepCopyList
(
new
CopyOnWriteArrayList
<>(
entryRel
),
GroupResult
.
class
);
cachedMaterials
=
ProductionDeepCopyUtil
.
deepCopyList
(
materials
,
Material
.
class
);
}
/**
* 禁忌搜索(优化版)
*/
public
Chromosome
search
(
Chromosome
chromosome
,
VariableNeighborhoodSearch
vns
,
GeneticDecoder
decoder
,
List
<
Machine
>
machines
)
{
log
(
"禁忌搜索 - 开始执行"
,
true
);
Chromosome
current
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
Chromosome
best
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
this
.
bestFitness
=
best
.
getFitnessLevel
().
clone
();
writeKpi
(
best
);
// 记录初始KPI用于计算改进率
double
[]
initialFitnessLevel
=
best
.
getFitnessLevel
().
clone
();
double
initialFitness
=
best
.
getFitness
();
int
iterations
=
0
;
int
improveCount
=
0
;
int
noImprovementCount
=
0
;
int
maxNoImprovement
=
15
;
// 降低到15次无改进则停止
int
maxIterations
=
Math
.
min
(
cachedAllOperations
.
size
(),
80
);
// 降低到最多80次
// 改进率监控
int
stagnantWindow
=
10
;
int
[]
recentImprovements
=
new
int
[
stagnantWindow
];
double
improvementRateThreshold
=
0.1
;
// 10%改进率阈值
// 多样性参数
int
diversificationInterval
=
20
;
// 每20次迭代尝试一次多样化
int
lastDiversificationIteration
=
0
;
log
(
String
.
format
(
"禁忌搜索 - 参数:最大迭代=%d, 最大无改进=%d"
,
maxIterations
,
maxNoImprovement
));
for
(
int
i
=
0
;
i
<
maxIterations
;
i
++)
{
iterations
++;
// 使用 VNS 生成邻域解(成功率排序后的策略)
Chromosome
neighbor
=
vns
.
generateNeighbor
(
current
);
if
(
neighbor
==
null
)
{
log
(
"禁忌搜索 - 生成邻居失败,跳过"
);
noImprovementCount
++;
// 记录无改进
if
(
iterations
<=
stagnantWindow
)
{
recentImprovements
[
iterations
-
1
]
=
0
;
}
continue
;
}
// 先检查禁忌(不需要解码!只需要 machineSelection 和 operationSequencing)
String
neighborGeneStr
=
neighbor
.
getGeneStr
();
String
currentGeneStr
=
current
.
getGeneStr
();
boolean
isTabu
=
isTabu
(
neighborGeneStr
);
// 方案 1:快速跳过和 current 一样的解(不用解码!)
if
(
neighborGeneStr
.
equals
(
currentGeneStr
))
{
// 和当前解一样,跳过,不用解码
addToTabuList
(
neighborGeneStr
);
noImprovementCount
++;
if
(
iterations
<=
stagnantWindow
)
{
recentImprovements
[
iterations
-
1
]
=
0
;
}
continue
;
}
// 添加到禁忌表(无论是否接受都先记下来)
addToTabuList
(
neighborGeneStr
);
boolean
accept
=
false
;
boolean
isBetterThanBest
=
false
;
boolean
isBetterThanCurrent
=
false
;
// 解码(需要比较 fitness)
decode
(
decoder
,
neighbor
,
machines
);
isBetterThanBest
=
isBetter
(
neighbor
,
best
);
isBetterThanCurrent
=
isBetter
(
neighbor
,
current
);
// 判断是否接受这个邻居
if
(!
isTabu
)
{
// 非禁忌,接受
accept
=
true
;
}
else
if
(
isBetterThanBest
)
{
// 禁忌但比最优解好(渴望准则),接受
log
(
"禁忌搜索 - 触发渴望准则,接受禁忌解"
);
accept
=
true
;
}
// else:禁忌且没有比最优解好,不接受
boolean
improvedThisIteration
=
false
;
if
(
accept
)
{
// 接受这个邻居
current
=
ProductionDeepCopyUtil
.
deepCopy
(
neighbor
,
Chromosome
.
class
);
// 更新最优解
if
(
isBetterThanBest
)
{
best
=
ProductionDeepCopyUtil
.
deepCopy
(
current
,
Chromosome
.
class
);
this
.
bestFitness
=
best
.
getFitnessLevel
().
clone
();
writeKpi
(
best
);
noImprovementCount
=
0
;
improveCount
++;
improvedThisIteration
=
true
;
logTabuImprovement
(
best
,
initialFitnessLevel
,
initialFitness
,
iterations
);
log
(
String
.
format
(
"禁忌搜索 - 找到更好解,迭代=%d"
,
iterations
),
true
);
}
else
if
(
isBetterThanCurrent
)
{
// 比当前解好但没有比最优解好
noImprovementCount
=
0
;
improvedThisIteration
=
true
;
}
else
{
// 没有改进
noImprovementCount
++;
}
}
else
{
// 不接受,无改进计数+1
noImprovementCount
++;
}
// 记录本次改进情况
if
(
iterations
<=
stagnantWindow
)
{
recentImprovements
[
iterations
-
1
]
=
improvedThisIteration
?
1
:
0
;
}
// 每10次迭代输出一次状态
if
(
iterations
%
10
==
0
)
{
log
(
String
.
format
(
"禁忌搜索 - 迭代%d/%d, 改进数=%d, 无改进连续=%d, 改进率=%.2f%%"
,
iterations
,
maxIterations
,
improveCount
,
noImprovementCount
,
iterations
>
0
?
(
double
)
improveCount
/
iterations
*
100
:
0
));
}
// 检查提前停止条件
boolean
shouldStop
=
false
;
String
stopReason
=
""
;
if
(
noImprovementCount
>=
maxNoImprovement
)
{
shouldStop
=
true
;
stopReason
=
String
.
format
(
"连续%d次无改进"
,
maxNoImprovement
);
}
else
if
(
iterations
>=
stagnantWindow
)
{
double
recentImproveRate
=
calculateRecentImprovementRate
(
recentImprovements
,
stagnantWindow
);
if
(
recentImproveRate
<
improvementRateThreshold
)
{
shouldStop
=
true
;
stopReason
=
String
.
format
(
"最近%d次迭代改进率过低(%.2f%%)"
,
stagnantWindow
,
recentImproveRate
*
100
);
}
}
if
(
shouldStop
)
{
log
(
String
.
format
(
"禁忌搜索 - 提前停止:%s"
,
stopReason
));
logTabuFinalSummary
(
best
,
initialFitnessLevel
,
initialFitness
,
iterations
,
improveCount
);
break
;
}
}
logTabuFinalSummary
(
best
,
initialFitnessLevel
,
initialFitness
,
iterations
,
improveCount
);
log
(
String
.
format
(
"禁忌搜索 - 结束,总迭代=%d"
,
iterations
),
true
);
return
best
;
}
private
void
writeKpi
(
Chromosome
chromosome
)
{
String
fitness
=
""
;
double
[]
fitness1
=
chromosome
.
getFitnessLevel
();
for
(
int
i
=
0
;
i
<
fitness1
.
length
;
i
++)
{
fitness
+=
fitness1
[
i
]
+
","
;
}
log
(
String
.
format
(
"变邻域搜索 - kpi:%s"
,
fitness
),
true
);
}
/**
* 记录禁忌搜索改进详情
*/
private
void
logTabuImprovement
(
Chromosome
best
,
double
[]
initialFitnessLevel
,
double
initialFitness
,
int
iteration
)
{
StringBuilder
sb
=
new
StringBuilder
(
"禁忌搜索 - 改进详情: 迭代"
+
iteration
+
", "
);
double
[]
currentFitness
=
best
.
getFitnessLevel
();
for
(
int
i
=
0
;
i
<
currentFitness
.
length
;
i
++)
{
double
improvement
=
currentFitness
[
i
]
-
initialFitnessLevel
[
i
];
sb
.
append
(
String
.
format
(
"KPI%d: %.4f→%.4f(+%.4f) "
,
i
+
1
,
initialFitnessLevel
[
i
],
currentFitness
[
i
],
improvement
));
}
double
totalImprovement
=
best
.
getFitness
()
-
initialFitness
;
sb
.
append
(
String
.
format
(
"总Fitness: %.4f→%.4f(+%.4f)"
,
initialFitness
,
best
.
getFitness
(),
totalImprovement
));
log
(
sb
.
toString
());
}
/**
* 计算最近改进率
*/
private
double
calculateRecentImprovementRate
(
int
[]
recentImprovements
,
int
windowSize
)
{
int
improveCount
=
0
;
for
(
int
i
=
0
;
i
<
windowSize
;
i
++)
{
improveCount
+=
recentImprovements
[
i
];
}
return
(
double
)
improveCount
/
windowSize
;
}
/**
* 记录禁忌搜索最终总结
*/
private
void
logTabuFinalSummary
(
Chromosome
best
,
double
[]
initialFitnessLevel
,
double
initialFitness
,
int
totalIterations
,
int
improveCount
)
{
StringBuilder
sb
=
new
StringBuilder
(
"禁忌搜索 - 最终总结: "
);
double
[]
currentFitness
=
best
.
getFitnessLevel
();
sb
.
append
(
String
.
format
(
"总迭代%d次, 成功改进%d次, 改进率%.2f%%. "
,
totalIterations
,
improveCount
,
totalIterations
>
0
?
(
double
)
improveCount
/
totalIterations
*
100
:
0
));
for
(
int
i
=
0
;
i
<
currentFitness
.
length
;
i
++)
{
double
improvement
=
currentFitness
[
i
]
-
initialFitnessLevel
[
i
];
sb
.
append
(
String
.
format
(
"KPI%d: %.4f→%.4f(%.2f%%) "
,
i
+
1
,
initialFitnessLevel
[
i
],
currentFitness
[
i
],
initialFitnessLevel
[
i
]
>
0
?
improvement
/
initialFitnessLevel
[
i
]
*
100
:
0
));
}
double
totalImprovement
=
best
.
getFitness
()
-
initialFitness
;
sb
.
append
(
String
.
format
(
"总Fitness: %.4f→%.4f(%.2f%%)"
,
initialFitness
,
best
.
getFitness
(),
initialFitness
>
0
?
totalImprovement
/
initialFitness
*
100
:
0
));
log
(
sb
.
toString
());
}
/**
* 检查解是否在禁忌表中
*/
...
...
@@ -42,23 +281,50 @@ public class TabuSearch {
}
/**
* 添加解到禁忌表
* 添加解到禁忌表
(FIFO策略)
*/
public
void
addToTabuList
(
String
G
eneStr
)
{
tabuList
.
add
(
G
eneStr
);
public
void
addToTabuList
(
String
g
eneStr
)
{
tabuList
.
add
(
g
eneStr
);
if
(
tabuList
.
size
()
>
tabuListSize
)
{
// 移除最早加入的禁忌解(FIFO策略)
Iterator
<
String
>
iterator
=
tabuList
.
iterator
();
iterator
.
next
();
iterator
.
remove
();
// 移除最早加入的禁忌解
tabuList
.
remove
(
0
);
}
}
private
void
decode
(
GeneticDecoder
decoder
,
Chromosome
chromosome
,
List
<
Machine
>
machines
)
{
chromosome
.
setResult
(
new
CopyOnWriteArrayList
<>());
// 缓存 Machine 列表(第一次调用时缓存)
if
(
cachedMachines
==
null
)
{
cachedMachines
=
ProductionDeepCopyUtil
.
deepCopyList
(
machines
,
Machine
.
class
);
}
// 使用缓存的列表,避免重复深拷贝
chromosome
.
setMachines
(
ProductionDeepCopyUtil
.
deepCopyList
(
cachedMachines
,
Machine
.
class
));
chromosome
.
setOrders
(
ProductionDeepCopyUtil
.
deepCopyList
(
new
CopyOnWriteArrayList
<>(
cachedOrders
),
Order
.
class
));
chromosome
.
setOperatRel
(
ProductionDeepCopyUtil
.
deepCopyList
(
new
CopyOnWriteArrayList
<>(
cachedEntryRel
),
GroupResult
.
class
));
chromosome
.
setMaterials
(
ProductionDeepCopyUtil
.
deepCopyList
(
cachedMaterials
,
Material
.
class
));
chromosome
.
setAllOperations
(
ProductionDeepCopyUtil
.
deepCopyList
(
new
CopyOnWriteArrayList
<>(
cachedAllOperations
),
Entry
.
class
));
// 加载锁定工单到ResultOld
List
<
GAScheduleResult
>
lockedOrders
=
GlobalCacheUtil
.
get
(
"locked_orders_"
+
chromosome
.
getScenarioID
());
if
(
lockedOrders
!=
null
&&
!
lockedOrders
.
isEmpty
())
{
chromosome
.
setResultOld
(
ProductionDeepCopyUtil
.
deepCopyList
(
lockedOrders
,
GAScheduleResult
.
class
));
}
else
{
chromosome
.
setResultOld
(
new
CopyOnWriteArrayList
<>());
}
decoder
.
decodeChromosomeWithCache
(
chromosome
,
true
);
}
/**
* 比较两个染色体的优劣(基于fitnessLevel多层次比较)
*/
private
boolean
isBetter
(
Chromosome
c1
,
Chromosome
c2
)
{
return
fitnessCalculator
.
isBetter
(
c1
,
c2
);
}
...
...
src/main/java/com/aps/service/Algorithm/TabuSearchWithSA.java
deleted
100644 → 0
View file @
932c42d2
package
com
.
aps
.
service
.
Algorithm
;
import
com.aps.common.util.ProductionDeepCopyUtil
;
import
com.aps.entity.Algorithm.*
;
import
com.aps.entity.basic.Entry
;
import
com.aps.entity.basic.GlobalParam
;
import
java.util.*
;
/**
* 禁忌搜索+模拟退火混合算法
*/
public
class
TabuSearchWithSA
{
private
final
Random
rnd
=
new
Random
();
private
GlobalParam
globalParam
;
private
List
<
Entry
>
allOperations
;
private
List
<
GlobalOperationInfo
>
globalOpList
;
private
FitnessCalculator
fitnessCalculator
;
private
ObjectiveWeights
objectiveWeights
;
// 禁忌表
private
List
<
Chromosome
>
tabuList
;
private
int
tabuListSize
=
50
;
public
TabuSearchWithSA
(
GlobalParam
globalParam
,
List
<
Entry
>
allOperations
,
List
<
GlobalOperationInfo
>
globalOpList
,
FitnessCalculator
fitnessCalculator
,
ObjectiveWeights
objectiveWeights
)
{
this
.
globalParam
=
globalParam
;
this
.
allOperations
=
allOperations
;
this
.
globalOpList
=
globalOpList
;
this
.
fitnessCalculator
=
fitnessCalculator
;
this
.
objectiveWeights
=
objectiveWeights
;
this
.
tabuList
=
new
ArrayList
<>();
}
/**
* 禁忌搜索+模拟退火混合搜索
*/
public
Chromosome
search
(
Chromosome
chromosome
,
GeneticDecoder
decoder
,
ScheduleParams
param
)
{
Chromosome
current
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
Chromosome
best
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
// 初始化温度
double
temperature
=
100.0
;
double
coolingRate
=
0.95
;
int
iterations
=
0
;
int
maxIterations
=
1000
;
int
noImprovementCount
=
0
;
int
maxNoImprovement
=
100
;
while
(
iterations
<
maxIterations
&&
noImprovementCount
<
maxNoImprovement
)
{
// 生成邻域解
List
<
Chromosome
>
neighbors
=
generateNeighbors
(
current
);
// 过滤禁忌解
List
<
Chromosome
>
validNeighbors
=
filterTabuSolutions
(
neighbors
);
// 评估所有邻域解
Chromosome
bestNeighbor
=
null
;
double
bestNeighborFitness
=
Double
.
NEGATIVE_INFINITY
;
for
(
Chromosome
neighbor
:
validNeighbors
)
{
decode
(
decoder
,
neighbor
,
param
);
if
(
neighbor
.
getFitness
()
>
bestNeighborFitness
)
{
bestNeighborFitness
=
neighbor
.
getFitness
();
bestNeighbor
=
neighbor
;
}
}
if
(
bestNeighbor
!=
null
)
{
// 计算能量差
decode
(
decoder
,
current
,
param
);
double
energyDifference
=
bestNeighbor
.
getFitness
()
-
current
.
getFitness
();
// 结合模拟退火的概率接受机制
if
(
energyDifference
>
0
||
rnd
.
nextDouble
()
<
Math
.
exp
(
energyDifference
/
temperature
))
{
// 更新当前解
current
=
bestNeighbor
;
// 更新禁忌表
addToTabuList
(
current
);
// 更新最优解
if
(
isBetter
(
current
,
best
))
{
best
=
current
;
noImprovementCount
=
0
;
}
else
{
noImprovementCount
++;
}
}
}
// 降温
temperature
*=
coolingRate
;
iterations
++;
}
return
best
;
}
/**
* 生成邻域解
*/
private
List
<
Chromosome
>
generateNeighbors
(
Chromosome
chromosome
)
{
List
<
Chromosome
>
neighbors
=
new
ArrayList
<>();
// 生成多个邻域解
for
(
int
i
=
0
;
i
<
10
;
i
++)
{
int
neighborType
=
rnd
.
nextInt
(
4
);
switch
(
neighborType
)
{
case
0
:
neighbors
.
add
(
generateSwapNeighbor
(
chromosome
));
break
;
case
1
:
neighbors
.
add
(
generateReverseNeighbor
(
chromosome
));
break
;
case
2
:
neighbors
.
add
(
generateInsertNeighbor
(
chromosome
));
break
;
case
3
:
neighbors
.
add
(
generateMachineChangeNeighbor
(
chromosome
));
break
;
}
}
return
neighbors
;
}
/**
* 过滤禁忌解
*/
private
List
<
Chromosome
>
filterTabuSolutions
(
List
<
Chromosome
>
neighbors
)
{
List
<
Chromosome
>
validNeighbors
=
new
ArrayList
<>();
for
(
Chromosome
neighbor
:
neighbors
)
{
if
(!
isTabu
(
neighbor
))
{
validNeighbors
.
add
(
neighbor
);
}
}
// 如果没有有效邻域解,返回所有邻域解
if
(
validNeighbors
.
isEmpty
())
{
return
neighbors
;
}
return
validNeighbors
;
}
/**
* 检查解是否在禁忌表中
*/
private
boolean
isTabu
(
Chromosome
chromosome
)
{
for
(
Chromosome
tabuChromosome
:
tabuList
)
{
if
(
chromosome
.
getGeneStr
().
equals
(
tabuChromosome
.
getGeneStr
()))
{
return
true
;
}
}
return
false
;
}
/**
* 添加解到禁忌表
*/
private
void
addToTabuList
(
Chromosome
chromosome
)
{
tabuList
.
add
(
chromosome
);
if
(
tabuList
.
size
()
>
tabuListSize
)
{
tabuList
.
remove
(
0
);
}
}
/**
* 生成交换邻域解
*/
private
Chromosome
generateSwapNeighbor
(
Chromosome
chromosome
)
{
Chromosome
neighbor
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
List
<
Integer
>
os
=
neighbor
.
getOperationSequencing
();
if
(
os
.
size
()
>=
2
)
{
int
idx1
=
rnd
.
nextInt
(
os
.
size
());
int
idx2
=
rnd
.
nextInt
(
os
.
size
());
while
(
idx2
==
idx1
)
{
idx2
=
rnd
.
nextInt
(
os
.
size
());
}
Collections
.
swap
(
os
,
idx1
,
idx2
);
neighbor
.
setOperationSequencing
(
os
);
}
return
neighbor
;
}
/**
* 生成反转邻域解
*/
private
Chromosome
generateReverseNeighbor
(
Chromosome
chromosome
)
{
Chromosome
neighbor
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
List
<
Integer
>
os
=
neighbor
.
getOperationSequencing
();
if
(
os
.
size
()
>=
2
)
{
int
start
=
rnd
.
nextInt
(
os
.
size
());
int
end
=
rnd
.
nextInt
(
os
.
size
());
while
(
end
<=
start
)
{
end
=
rnd
.
nextInt
(
os
.
size
());
}
Collections
.
reverse
(
os
.
subList
(
start
,
end
+
1
));
neighbor
.
setOperationSequencing
(
os
);
}
return
neighbor
;
}
/**
* 生成插入邻域解
*/
private
Chromosome
generateInsertNeighbor
(
Chromosome
chromosome
)
{
Chromosome
neighbor
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
List
<
Integer
>
os
=
neighbor
.
getOperationSequencing
();
if
(
os
.
size
()
>=
2
)
{
int
idx1
=
rnd
.
nextInt
(
os
.
size
());
int
idx2
=
rnd
.
nextInt
(
os
.
size
());
while
(
idx2
==
idx1
)
{
idx2
=
rnd
.
nextInt
(
os
.
size
());
}
int
value
=
os
.
remove
(
idx1
);
os
.
add
(
idx2
,
value
);
neighbor
.
setOperationSequencing
(
os
);
}
return
neighbor
;
}
/**
* 生成机器选择邻域解
*/
private
Chromosome
generateMachineChangeNeighbor
(
Chromosome
chromosome
)
{
Chromosome
neighbor
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
List
<
Integer
>
ms
=
neighbor
.
getMachineSelection
();
if
(!
ms
.
isEmpty
())
{
int
idx
=
rnd
.
nextInt
(
ms
.
size
());
GlobalOperationInfo
globalOp
=
globalOpList
.
get
(
idx
);
Entry
op
=
globalOp
.
getOp
();
if
(
op
.
getMachineOptions
().
size
()
>
1
)
{
int
currentMachineSeq
=
ms
.
get
(
idx
);
List
<
Integer
>
availableMachines
=
new
ArrayList
<>();
for
(
int
i
=
1
;
i
<=
op
.
getMachineOptions
().
size
();
i
++)
{
if
(
i
!=
currentMachineSeq
)
{
availableMachines
.
add
(
i
);
}
}
if
(!
availableMachines
.
isEmpty
())
{
int
newMachineSeq
=
availableMachines
.
get
(
rnd
.
nextInt
(
availableMachines
.
size
()));
ms
.
set
(
idx
,
newMachineSeq
);
neighbor
.
setMachineSelection
(
ms
);
}
}
}
return
neighbor
;
}
/**
* 解码染色体
*/
private
void
decode
(
GeneticDecoder
decoder
,
Chromosome
chromosome
,
ScheduleParams
param
)
{
chromosome
.
setResult
(
new
java
.
util
.
concurrent
.
CopyOnWriteArrayList
<>());
decoder
.
decodeChromosomeWithCache
(
chromosome
);
if
(
chromosome
.
getFitness
()
==
0
)
{
chromosome
.
setFitness
(
fitnessCalculator
.
calculateFitness
(
chromosome
,
objectiveWeights
));
}
}
/**
* 比较两个染色体的优劣
*/
private
boolean
isBetter
(
Chromosome
c1
,
Chromosome
c2
)
{
return
c1
.
getFitness
()
>
c2
.
getFitness
();
}
}
\ No newline at end of file
src/main/java/com/aps/service/Algorithm/VariableNeighborhoodSearch.java
View file @
8a7de711
package
com
.
aps
.
service
.
Algorithm
;
import
com.aps.common.util.FileHelper
;
import
com.aps.common.util.GlobalCacheUtil
;
import
com.aps.common.util.ProductionDeepCopyUtil
;
import
com.aps.entity.Algorithm.*
;
import
com.aps.entity.Algorithm.IDAndChildID.GroupResult
;
import
com.aps.entity.basic.*
;
import
java.util.*
;
...
...
@@ -16,23 +19,184 @@ import java.util.stream.Collectors;
public
class
VariableNeighborhoodSearch
{
private
final
Random
rnd
=
new
Random
();
private
void
log
(
String
message
)
{
log
(
message
,
true
);
}
private
void
log
(
String
message
,
boolean
enableLogging
)
{
if
(
enableLogging
)
{
FileHelper
.
writeLogFile
(
message
);
}
}
private
List
<
Entry
>
allOperations
;
private
FitnessCalculator
fitnessCalculator
;
private
List
<
Order
>
orders
;
private
List
<
Material
>
materials
;
private
List
<
GroupResult
>
_entryRel
;
private
Map
<
String
,
Entry
>
entrys
;
private
Map
<
Integer
,
Entry
>
entrybyids
;
public
VariableNeighborhoodSearch
(
List
<
Entry
>
allOperations
,
FitnessCalculator
fitnessCalculator
)
{
// 预检查:是否有工序有多个机器选项
private
boolean
hasMultipleMachineOptions
=
false
;
// 策略成功率统计
private
int
[]
strategySuccessCount
=
new
int
[
4
];
private
int
[]
strategyTotalCount
=
new
int
[
4
];
// 强制策略轮换:跟踪最后使用的策略
private
int
lastUsedStrategy
=
-
1
;
private
int
consecutiveSameStrategyCount
=
0
;
private
static
final
int
MAX_CONSECUTIVE_SAME_STRATEGY
=
3
;
// 最多连续使用同一个策略3次
// 缓存的深拷贝列表,用于解码优化
private
List
<
Machine
>
cachedMachines
;
private
List
<
Order
>
cachedOrders
;
private
List
<
GroupResult
>
cachedEntryRel
;
private
List
<
Material
>
cachedMaterials
;
private
List
<
Entry
>
cachedAllOperations
;
// 邻域结构成功率统计(用于 search() 方法)
private
static
class
NeighborhoodWithStats
{
NeighborhoodStructure
structure
;
int
successCount
;
int
totalCount
;
NeighborhoodWithStats
(
NeighborhoodStructure
structure
)
{
this
.
structure
=
structure
;
this
.
successCount
=
0
;
this
.
totalCount
=
0
;
}
double
getSuccessRate
()
{
return
totalCount
>
0
?
(
double
)
successCount
/
totalCount
:
0.5
;
}
}
private
List
<
NeighborhoodWithStats
>
neighborhoodsWithStats
;
private
int
maxNoImproveRounds
=
1
;
public
void
setMaxNoImproveRounds
(
int
maxNoImproveRounds
)
{
this
.
maxNoImproveRounds
=
maxNoImproveRounds
;
}
public
VariableNeighborhoodSearch
(
List
<
Entry
>
allOperations
,
List
<
Order
>
orders
,
List
<
Material
>
materials
,
List
<
GroupResult
>
entryRel
,
FitnessCalculator
fitnessCalculator
)
{
this
(
allOperations
,
orders
,
materials
,
entryRel
,
fitnessCalculator
,
3
);
}
public
VariableNeighborhoodSearch
(
List
<
Entry
>
allOperations
,
List
<
Order
>
orders
,
List
<
Material
>
materials
,
List
<
GroupResult
>
entryRel
,
FitnessCalculator
fitnessCalculator
,
int
maxNoImproveRounds
)
{
this
.
maxNoImproveRounds
=
maxNoImproveRounds
;
this
.
allOperations
=
allOperations
;
this
.
orders
=
orders
;
this
.
materials
=
materials
;
_entryRel
=
entryRel
;
this
.
fitnessCalculator
=
fitnessCalculator
;
Map
<
Integer
,
Object
>
mp
=
buildEntryKey
();
entrys
=(
Map
<
String
,
Entry
>)
mp
.
get
(
1
);
entrybyids
=(
Map
<
Integer
,
Entry
>)
mp
.
get
(
2
);
// 预检查:是否有工序有多个机器选项
for
(
Entry
entry
:
allOperations
)
{
if
(
entry
.
getMachineOptions
()
!=
null
&&
entry
.
getMachineOptions
().
size
()
>
1
)
{
hasMultipleMachineOptions
=
true
;
break
;
}
}
// 预缓存解码需要的深拷贝列表,避免重复拷贝
cachedAllOperations
=
ProductionDeepCopyUtil
.
deepCopyList
(
new
CopyOnWriteArrayList
<>(
allOperations
),
Entry
.
class
);
cachedOrders
=
ProductionDeepCopyUtil
.
deepCopyList
(
new
CopyOnWriteArrayList
<>(
orders
),
Order
.
class
);
cachedEntryRel
=
ProductionDeepCopyUtil
.
deepCopyList
(
new
CopyOnWriteArrayList
<>(
entryRel
),
GroupResult
.
class
);
cachedMaterials
=
ProductionDeepCopyUtil
.
deepCopyList
(
materials
,
Material
.
class
);
// 初始化邻域结构统计
neighborhoodsWithStats
=
new
ArrayList
<>();
List
<
NeighborhoodStructure
>
initialNeighborhoods
=
defineNeighborhoodsInternal
();
for
(
NeighborhoodStructure
ns
:
initialNeighborhoods
)
{
neighborhoodsWithStats
.
add
(
new
NeighborhoodWithStats
(
ns
));
}
//log("VariableNeighborhoodSearch初始化: hasMultipleMachineOptions=" + hasMultipleMachineOptions);
}
/**
* 内部方法:定义邻域结构(不排序)
*/
private
List
<
NeighborhoodStructure
>
defineNeighborhoodsInternal
()
{
List
<
NeighborhoodStructure
>
neighborhoods
=
new
ArrayList
<>();
//瓶颈工序机器选择变异
neighborhoods
.
add
(
new
NeighborhoodStructure
(
"SmartBottleneckChange"
,
this
::
ChangeMachineForBottleneckOpWrapper
));
//瓶颈工序在相同设备上移动
neighborhoods
.
add
(
new
NeighborhoodStructure
(
"moveBottleneckSameMachine"
,
this
::
moveBottleneckSameMachineWrapper
));
//瓶颈工序往前移动
neighborhoods
.
add
(
new
NeighborhoodStructure
(
"MoveBottleneckForward"
,
this
::
moveBottleneckForwardWrapper
));
//非瓶颈工序往后移动
neighborhoods
.
add
(
new
NeighborhoodStructure
(
"MoveNonBottleneckBackward"
,
this
::
moveNonBottleneckBackwardWrapper
));
//// 交换相同设备的两个工序
neighborhoods
.
add
(
new
NeighborhoodStructure
(
"SwapSameMachine"
,
this
::
generateSameMachineSwapNeighbor
));
// 交换两个工序的顺序
neighborhoods
.
add
(
new
NeighborhoodStructure
(
"Swap"
,
this
::
generateSwapNeighborWrapper
));
// 反转一个工序子序列
neighborhoods
.
add
(
new
NeighborhoodStructure
(
"Reverse"
,
this
::
generateReverseNeighborWrapper
));
// 插入一个工序到另一个位置
neighborhoods
.
add
(
new
NeighborhoodStructure
(
"Insert"
,
this
::
generateInsertNeighborWrapper
));
// 机器选择变异
neighborhoods
.
add
(
new
NeighborhoodStructure
(
"MachineChange"
,
this
::
generateMachineChangeNeighbor
));
return
neighborhoods
;
}
/**
* 定义邻域结构(按成功率排序)
*/
private
List
<
NeighborhoodStructure
>
defineNeighborhoods
()
{
// 按成功率排序
List
<
NeighborhoodWithStats
>
sorted
=
new
ArrayList
<>(
neighborhoodsWithStats
);
sorted
.
sort
((
a
,
b
)
->
Double
.
compare
(
b
.
getSuccessRate
(),
a
.
getSuccessRate
()));
// 提取 NeighborhoodStructure
List
<
NeighborhoodStructure
>
result
=
new
ArrayList
<>();
// for (NeighborhoodWithStats ns : sorted) {
// result.add(ns.structure);
// }
int
maxNeighborhoods
=
Math
.
min
(
7
,
sorted
.
size
());
for
(
int
i
=
0
;
i
<
maxNeighborhoods
;
i
++)
{
result
.
add
(
sorted
.
get
(
i
).
structure
);
}
return
result
;
}
/**
* 记录邻域结构使用结果
*/
private
void
recordNeighborhoodResult
(
NeighborhoodStructure
structure
,
boolean
success
)
{
for
(
NeighborhoodWithStats
ns
:
neighborhoodsWithStats
)
{
if
(
ns
.
structure
.
equals
(
structure
))
{
ns
.
totalCount
++;
if
(
success
)
{
ns
.
successCount
++;
}
break
;
}
}
}
/**
...
...
@@ -53,58 +217,173 @@ public class VariableNeighborhoodSearch {
* 对单个个体进行变邻域搜索
*/
public
Chromosome
search
(
Chromosome
chromosome
,
GeneticDecoder
decoder
,
List
<
Machine
>
machines
)
{
log
(
"变邻域搜索 - 开始执行"
,
true
);
// 深拷贝当前染色体
Chromosome
current
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
Chromosome
best
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
writeKpi
(
best
);
// 定义邻域结构
List
<
NeighborhoodStructure
>
neighborhoods
=
defineNeighborhoods
();
// 记录初始KPI用于跟踪改进
double
[]
initialFitnessLevel
=
best
.
getFitnessLevel
().
clone
();
double
initialFitness
=
best
.
getFitness
();
// 提前结束参数
int
noImproveRoundCount
=
0
;
// 无改进轮数计数
int
totalRounds
=
0
;
// 总轮数
int
totalImprovements
=
0
;
// 总改进次数
int
k
=
0
;
while
(
k
<
neighborhoods
.
size
())
{
// 随机选择一个邻域结构
// 按成功率排序获取邻域结构(先获取一次)
List
<
NeighborhoodStructure
>
neighborhoods
=
defineNeighborhoods
();
while
(
noImproveRoundCount
<
maxNoImproveRounds
)
{
totalRounds
++;
log
(
"变邻域搜索 - 轮次"
+
totalRounds
+
", K==="
+
k
);
NeighborhoodStructure
neighborhood
=
neighborhoods
.
get
(
k
);
// 找到对应的统计对象
NeighborhoodWithStats
neighborhoodWithStats
=
null
;
for
(
NeighborhoodWithStats
ns
:
neighborhoodsWithStats
)
{
if
(
ns
.
structure
.
equals
(
neighborhood
))
{
neighborhoodWithStats
=
ns
;
break
;
}
}
// 生成邻域解
Chromosome
neighbor
=
generateNeighbor
(
current
);
Chromosome
neighbor
=
generateNeighbor
(
current
,
neighborhood
);
if
(
neighbor
==
null
)
{
log
(
"变邻域搜索 - null"
);
if
(
neighborhoodWithStats
!=
null
)
{
recordNeighborhoodResult
(
neighborhood
,
false
);
}
k
++;
// 检查是否完成一轮
if
(
k
>=
neighborhoods
.
size
())
{
noImproveRoundCount
++;
log
(
String
.
format
(
"变邻域搜索 - 本轮无改进,连续无改进轮数: %d/%d"
,
noImproveRoundCount
,
maxNoImproveRounds
));
k
=
0
;
// 重置k,开始新一轮
}
continue
;
}
// 局部搜索
Chromosome
localBest
=
localSearch
(
neighbor
,
decoder
,
null
);
Chromosome
localBest
=
localSearch
(
neighbor
,
decoder
,
machines
);
// 邻域移动
if
(
isBetter
(
localBest
,
best
))
{
best
=
localBest
;
boolean
success
=
isBetter
(
localBest
,
best
);
if
(
success
)
{
best
=
ProductionDeepCopyUtil
.
deepCopy
(
localBest
,
Chromosome
.
class
);
writeKpi
(
best
);
current
=
localBest
;
k
=
0
;
// 重置邻域索引
noImproveRoundCount
=
0
;
// 重置无改进计数
totalImprovements
++;
logVNSImprovement
(
best
,
initialFitnessLevel
,
initialFitness
,
totalRounds
,
neighborhood
.
name
);
log
(
String
.
format
(
"变邻域搜索 - 邻域成功: %s"
,
neighborhood
.
name
),
true
);
}
else
{
k
++;
// 尝试下一个邻域
// 检查是否完成一轮
if
(
k
>=
neighborhoods
.
size
())
{
noImproveRoundCount
++;
log
(
String
.
format
(
"变邻域搜索 - 本轮无改进,连续无改进轮数: %d/%d"
,
noImproveRoundCount
,
maxNoImproveRounds
));
k
=
0
;
// 重置k,开始新一轮
}
}
// 记录结果
if
(
neighborhoodWithStats
!=
null
)
{
recordNeighborhoodResult
(
neighborhood
,
success
);
}
// 检查提前结束条件
if
(
noImproveRoundCount
>=
maxNoImproveRounds
)
{
log
(
String
.
format
(
"变邻域搜索 - 提前结束:连续%d轮无改进"
,
maxNoImproveRounds
));
logVNSFinalSummary
(
best
,
initialFitnessLevel
,
initialFitness
,
totalRounds
,
totalImprovements
);
break
;
}
}
if
(
noImproveRoundCount
<
maxNoImproveRounds
)
{
logVNSFinalSummary
(
best
,
initialFitnessLevel
,
initialFitness
,
totalRounds
,
totalImprovements
);
}
return
best
;
}
/**
*
定义邻域结构
*
记录变邻域搜索改进详情
*/
private
List
<
NeighborhoodStructure
>
defineNeighborhoods
()
{
List
<
NeighborhoodStructure
>
neighborhoods
=
new
ArrayList
<>();
private
void
logVNSImprovement
(
Chromosome
best
,
double
[]
initialFitnessLevel
,
double
initialFitness
,
int
round
,
String
neighborhoodName
)
{
StringBuilder
sb
=
new
StringBuilder
(
"变邻域搜索 - 改进详情: 轮次"
+
round
+
", 邻域="
+
neighborhoodName
+
", "
);
double
[]
currentFitness
=
best
.
getFitnessLevel
();
for
(
int
i
=
0
;
i
<
currentFitness
.
length
;
i
++)
{
double
improvement
=
currentFitness
[
i
]
-
initialFitnessLevel
[
i
];
sb
.
append
(
String
.
format
(
"KPI%d: %.4f→%.4f(+%.4f) "
,
i
+
1
,
initialFitnessLevel
[
i
],
currentFitness
[
i
],
improvement
));
}
// 邻域1:交换两个工序的顺序
neighborhoods
.
add
(
new
NeighborhoodStructure
(
"Swap"
,
this
::
swapNeighborhood
));
double
totalImprovement
=
best
.
getFitness
()
-
initialFitness
;
sb
.
append
(
String
.
format
(
"总Fitness: %.4f→%.4f(+%.4f)"
,
initialFitness
,
best
.
getFitness
(),
totalImprovement
));
log
(
sb
.
toString
(),
true
);
}
// 邻域2:反转一个工序子序列
neighborhoods
.
add
(
new
NeighborhoodStructure
(
"Reverse"
,
this
::
reverseNeighborhood
));
/**
* 记录变邻域搜索最终总结
*/
private
void
logVNSFinalSummary
(
Chromosome
best
,
double
[]
initialFitnessLevel
,
double
initialFitness
,
int
totalRounds
,
int
totalImprovements
)
{
StringBuilder
sb
=
new
StringBuilder
(
"变邻域搜索 - 最终总结: "
);
double
[]
currentFitness
=
best
.
getFitnessLevel
();
// 邻域3:插入一个工序到另一个位置
neighborhoods
.
add
(
new
NeighborhoodStructure
(
"Insert"
,
this
::
insertNeighborhood
));
sb
.
append
(
String
.
format
(
"总轮次%d次, 成功改进%d次, 改进率%.2f%%. "
,
totalRounds
,
totalImprovements
,
totalRounds
>
0
?
(
double
)
totalImprovements
/
totalRounds
*
100
:
0
));
// 邻域4:机器选择变异
neighborhoods
.
add
(
new
NeighborhoodStructure
(
"MachineChange"
,
this
::
machineChangeNeighborhood
));
// 记录各邻域结构的成功率
sb
.
append
(
"邻域成功率: "
);
for
(
NeighborhoodWithStats
ns
:
neighborhoodsWithStats
)
{
double
rate
=
ns
.
getSuccessRate
();
sb
.
append
(
String
.
format
(
"[%s: %d/%d(%.1f%%)] "
,
ns
.
structure
.
name
,
ns
.
successCount
,
ns
.
totalCount
,
rate
*
100
));
}
sb
.
append
(
"\n"
);
return
neighborhoods
;
// 记录KPI改进
for
(
int
i
=
0
;
i
<
currentFitness
.
length
;
i
++)
{
double
improvement
=
currentFitness
[
i
]
-
initialFitnessLevel
[
i
];
sb
.
append
(
String
.
format
(
"KPI%d: %.4f→%.4f(%.2f%%) "
,
i
+
1
,
initialFitnessLevel
[
i
],
currentFitness
[
i
],
initialFitnessLevel
[
i
]
>
0
?
improvement
/
initialFitnessLevel
[
i
]
*
100
:
0
));
}
double
totalImprovement
=
best
.
getFitness
()
-
initialFitness
;
sb
.
append
(
String
.
format
(
"总Fitness: %.4f→%.4f(%.2f%%)"
,
initialFitness
,
best
.
getFitness
(),
initialFitness
>
0
?
totalImprovement
/
initialFitness
*
100
:
0
));
log
(
sb
.
toString
());
}
private
void
writeKpi
(
Chromosome
chromosome
)
{
String
fitness
=
""
;
double
[]
fitness1
=
chromosome
.
getFitnessLevel
();
for
(
int
i
=
0
;
i
<
fitness1
.
length
;
i
++)
{
fitness
+=
fitness1
[
i
]
+
","
;
}
log
(
String
.
format
(
"变邻域搜索 - kpi:%s"
,
fitness
),
true
);
}
/**
* 定义邻域结构
*/
private
Chromosome
generateNeighbor
(
Chromosome
chromosome
,
NeighborhoodStructure
neighborhood
)
{
return
neighborhood
.
apply
(
chromosome
);
}
/**
* 生成邻域解 - 智能策略:优先处理瓶颈工序/设备
* 策略:
...
...
@@ -115,45 +394,574 @@ public class VariableNeighborhoodSearch {
public
Chromosome
generateNeighbor
(
Chromosome
chromosome
)
{
List
<
GAScheduleResult
>
results
=
chromosome
.
getResult
();
if
(
results
==
null
||
results
.
isEmpty
())
{
return
generateRandomNeighbor
(
chromosome
,
entrys
);
}
// 构建位置索引
Map
<
String
,
Integer
>
positionIndex
=
buildPositionIndex
(
chromosome
);
Map
<
Integer
,
Entry
>
positionToEntryIndex
=
buildPositionToEntryIndex
(
chromosome
,
entrys
);
Map
<
Integer
,
Object
>
obj
=
buildPositionToEntryIndex
(
chromosome
);
Map
<
Integer
,
Entry
>
positionToEntryIndex
=(
Map
<
Integer
,
Entry
>)
obj
.
get
(
1
);
List
<
List
<
Integer
>>
positionByPriority
=
(
List
<
List
<
Integer
>>)
obj
.
get
(
2
);
Map
<
String
,
Integer
>
MachinePositionIndex
=
buildEntryMachinePositionIndex
(
chromosome
);
// 1. 找出瓶颈设备
Long
bottleneckMachineId
=
findBottleneckMachine
(
chromosome
);
if
(
results
==
null
||
results
.
isEmpty
())
{
log
(
"generateNeighbor: results为空,使用随机邻域"
);
return
generateRandomNeighbor
(
chromosome
,
positionToEntryIndex
,
positionByPriority
);
}
// 1. 找出瓶颈设备和关键工序
Map
<
String
,
Object
>
bottleneckAnalysis
=
findBottleneckMachineWithDetails
(
chromosome
);
Long
bottleneckMachineId
=
(
Long
)
bottleneckAnalysis
.
get
(
"bottleneckMachineId"
);
List
<
GAScheduleResult
>
criticalOps
=
(
List
<
GAScheduleResult
>)
bottleneckAnalysis
.
get
(
"criticalOps"
);
logBottleneckAnalysis
(
bottleneckAnalysis
);
if
(
bottleneckMachineId
!=
null
&&
criticalOps
!=
null
&&
!
criticalOps
.
isEmpty
())
{
if
(
rnd
.
nextDouble
()
<
0.8
)
{
// 增加使用智能策略的概率
// 构建策略顺序,考虑成功率
List
<
Integer
>
strategyOrder
=
buildStrategyOrder
();
log
(
String
.
format
(
"瓶颈设备-策略顺序=%s, 关键工序数=%d"
,
strategyOrder
,
criticalOps
.
size
()));
Chromosome
result
=
null
;
for
(
int
attempt
=
0
;
attempt
<
strategyOrder
.
size
();
attempt
++)
{
int
strategyIndex
=
strategyOrder
.
get
(
attempt
);
// 如果没有多个机器选项,跳过策略1
if
(
strategyIndex
==
0
&&
!
hasMultipleMachineOptions
)
{
log
(
String
.
format
(
"跳过%d/4: 策略1-无多机器选项"
,
attempt
+
1
));
continue
;
}
strategyTotalCount
[
strategyIndex
]++;
if
(
strategyIndex
==
0
)
{
log
(
String
.
format
(
"尝试%d/4: 策略1-关键工序换设备"
,
attempt
+
1
));
result
=
tryChangeMachineForBottleneckOp
(
chromosome
,
criticalOps
,
MachinePositionIndex
,
positionToEntryIndex
,
positionByPriority
);
}
else
if
(
strategyIndex
==
1
)
{
log
(
String
.
format
(
"尝试%d/4: 策略2-关键工序往前移动"
,
attempt
+
1
));
result
=
tryMoveBottleneckOpForward
(
chromosome
,
criticalOps
,
positionIndex
,
positionByPriority
,
positionToEntryIndex
,
MachinePositionIndex
,
false
);
}
else
if
(
strategyIndex
==
2
)
{
log
(
String
.
format
(
"尝试%d/4: 策略3-相同设备工序交换"
,
attempt
+
1
));
result
=
tryMoveBottleneckOpForward
(
chromosome
,
criticalOps
,
positionIndex
,
positionByPriority
,
positionToEntryIndex
,
MachinePositionIndex
,
true
);
}
else
{
log
(
String
.
format
(
"尝试%d/4: 策略4-非瓶颈工序往后移动"
,
attempt
+
1
));
result
=
tryMoveNonBottleneckOpBackward
(
chromosome
,
bottleneckMachineId
,
positionIndex
,
positionByPriority
,
positionToEntryIndex
);
}
if
(
result
!=
null
)
{
strategySuccessCount
[
strategyIndex
]++;
// 更新策略使用跟踪信息
if
(
strategyIndex
==
lastUsedStrategy
)
{
consecutiveSameStrategyCount
++;
}
else
{
lastUsedStrategy
=
strategyIndex
;
consecutiveSameStrategyCount
=
1
;
}
logStrategyStats
();
log
(
String
.
format
(
"策略成功,使用策略%d (连续%d次)"
,
strategyIndex
+
1
,
consecutiveSameStrategyCount
));
return
result
;
}
log
(
"当前策略失败,尝试下一个..."
);
}
log
(
"所有瓶颈策略都失败,使用随机邻域"
);
}
}
else
{
log
(
"没有找到瓶颈设备或关键工序"
);
}
log
(
"使用随机邻域"
);
return
generateRandomNeighbor
(
chromosome
,
positionToEntryIndex
,
positionByPriority
);
}
/**
* 识别瓶颈设备及关键工序(更精准的分析)
* 优先选择订单数多的优先级组的工序
*/
private
Map
<
String
,
Object
>
findBottleneckMachineWithDetails
(
Chromosome
chromosome
)
{
Map
<
String
,
Object
>
result
=
new
HashMap
<>();
List
<
GAScheduleResult
>
allResults
=
chromosome
.
getResult
();
Map
<
Long
,
Double
>
utilization
=
calculateMachineUtilization
(
chromosome
);
Map
<
Long
,
List
<
GAScheduleResult
>>
machineOps
=
allResults
!=
null
?
allResults
.
stream
().
collect
(
Collectors
.
groupingBy
(
GAScheduleResult:
:
getMachineId
))
:
new
HashMap
<>();
if
(
utilization
.
isEmpty
())
{
result
.
put
(
"bottleneckMachineId"
,
null
);
result
.
put
(
"criticalOps"
,
new
ArrayList
<
GAScheduleResult
>());
result
.
put
(
"allResults"
,
allResults
);
return
result
;
}
// 找出利用率最高的设备
Long
bottleneckMachineId
=
utilization
.
entrySet
().
stream
()
.
max
(
Map
.
Entry
.
comparingByValue
())
.
map
(
Map
.
Entry
::
getKey
)
.
orElse
(
null
);
result
.
put
(
"bottleneckMachineId"
,
bottleneckMachineId
);
result
.
put
(
"utilization"
,
utilization
);
result
.
put
(
"allResults"
,
allResults
);
// 找出关键工序:瓶颈设备上的工序 + 延迟订单的工序
List
<
GAScheduleResult
>
criticalOps
=
new
ArrayList
<>();
if
(
bottleneckMachineId
!=
null
)
{
// 找出瓶颈设备上的工序
List
<
GAScheduleResult
>
bottleneckOps
=
findOpsOnBottleneckMachine
(
chromosome
,
bottleneckMachineId
);
criticalOps
.
addAll
(
machineOps
.
getOrDefault
(
bottleneckMachineId
,
new
ArrayList
<>()));
}
if
(!
bottleneckOps
.
isEmpty
())
{
// 70%概率优先处理瓶颈设备
if
(
rnd
.
nextDouble
()
<
0.7
)
{
int
strategy
=
rnd
.
nextInt
(
10
);
// 找出延迟的订单工序
List
<
GAScheduleResult
>
delayedOps
=
findDelayedOperations
(
chromosome
);
criticalOps
.
addAll
(
delayedOps
);
if
(
strategy
<=
3
)
{
// 策略1:瓶颈设备上的工序换设备
return
tryChangeMachineForBottleneckOp
(
chromosome
,
bottleneckOps
,
entrys
,
MachinePositionIndex
);
// 去重
Set
<
Integer
>
seenOpIds
=
new
HashSet
<>();
List
<
GAScheduleResult
>
uniqueCriticalOps
=
new
ArrayList
<>();
for
(
GAScheduleResult
op
:
criticalOps
)
{
if
(!
seenOpIds
.
contains
(
op
.
getOperationId
()))
{
seenOpIds
.
add
(
op
.
getOperationId
());
uniqueCriticalOps
.
add
(
op
);
}
}
// 优先选择订单数多的优先级组的工序
if
(!
uniqueCriticalOps
.
isEmpty
())
{
// 构建优先级->订单数的映射
Map
<
Double
,
Set
<
Integer
>>
priorityToGroupIds
=
new
HashMap
<>();
for
(
GAScheduleResult
op
:
uniqueCriticalOps
)
{
Entry
entry
=
entrybyids
.
get
(
op
.
getOperationId
());
if
(
entry
!=
null
)
{
double
priority
=
entry
.
getPriority
();
priorityToGroupIds
.
computeIfAbsent
(
priority
,
k
->
new
HashSet
<>()).
add
(
op
.
getGroupId
());
}
}
// 按订单数从多到少排序关键工序
uniqueCriticalOps
.
sort
((
op1
,
op2
)
->
{
Entry
entry1
=
entrybyids
.
get
(
op1
.
getOperationId
());
Entry
entry2
=
entrybyids
.
get
(
op2
.
getOperationId
());
if
(
entry1
==
null
||
entry2
==
null
)
{
return
0
;
}
else
if
(
strategy
<=
8
)
{
// 策略2:瓶颈设备上的工序往前移动
return
tryMoveBottleneckOpForward
(
chromosome
,
bottleneckOps
,
positionIndex
,
positionToEntryIndex
,
entrys
);
}
else
if
(
strategy
<=
10
)
{
// 策略3:非瓶颈设备上的工序往后移动
return
tryMoveNonBottleneckOpBackward
(
chromosome
,
bottleneckMachineId
,
positionIndex
,
positionToEntryIndex
,
entrys
);
int
size1
=
priorityToGroupIds
.
getOrDefault
(
entry1
.
getPriority
(),
new
HashSet
<>()).
size
();
int
size2
=
priorityToGroupIds
.
getOrDefault
(
entry2
.
getPriority
(),
new
HashSet
<>()).
size
();
// 订单数多的优先级排前面
int
sizeCompare
=
Integer
.
compare
(
size2
,
size1
);
if
(
sizeCompare
!=
0
)
{
return
sizeCompare
;
}
// 订单数相同时,按优先级排序
return
Double
.
compare
(
entry2
.
getPriority
(),
entry1
.
getPriority
());
});
}
result
.
put
(
"criticalOps"
,
uniqueCriticalOps
);
result
.
put
(
"delayedOps"
,
delayedOps
);
return
result
;
}
/**
* 找出延迟的工序
*/
private
List
<
GAScheduleResult
>
findDelayedOperations
(
Chromosome
chromosome
)
{
List
<
GAScheduleResult
>
delayedOps
=
new
ArrayList
<>();
List
<
GAScheduleResult
>
results
=
chromosome
.
getResult
();
if
(
results
==
null
||
results
.
isEmpty
())
{
return
delayedOps
;
}
// 按订单分组,计算订单完成时间
Map
<
Integer
,
Integer
>
orderCompletionTimes
=
new
HashMap
<>();
for
(
GAScheduleResult
result
:
results
)
{
int
groupId
=
result
.
getGroupId
();
int
endTime
=
result
.
getEndTime
();
orderCompletionTimes
.
put
(
groupId
,
Math
.
max
(
orderCompletionTimes
.
getOrDefault
(
groupId
,
0
),
endTime
));
}
// 找出完成时间较晚的订单(超过平均完成时间的1.5倍)
if
(!
orderCompletionTimes
.
isEmpty
())
{
double
avgCompletionTime
=
orderCompletionTimes
.
values
().
stream
()
.
mapToInt
(
Integer:
:
intValue
)
.
average
()
.
orElse
(
0
);
double
threshold
=
avgCompletionTime
*
1.5
;
Set
<
Integer
>
delayedOrderIds
=
orderCompletionTimes
.
entrySet
().
stream
()
.
filter
(
e
->
e
.
getValue
()
>
threshold
)
.
map
(
Map
.
Entry
::
getKey
)
.
collect
(
Collectors
.
toSet
());
// 收集这些延迟订单的工序
for
(
GAScheduleResult
result
:
results
)
{
if
(
delayedOrderIds
.
contains
(
result
.
getGroupId
()))
{
delayedOps
.
add
(
result
);
}
}
}
return
delayedOps
;
}
/**
* 瓶颈工序分析结果类
*/
private
static
class
BottleneckOperationAnalysis
{
GAScheduleResult
operation
;
double
bottleneckScore
;
// 瓶颈评分(越高越可能是瓶颈)
int
waitTime
;
// 工序等待时间(前一道工序结束到本工序开始)
int
machineWaitTime
;
// 设备等待时间(设备上一道工序结束到本工序开始)
boolean
onCriticalPath
;
// 是否在关键路径上
double
delayContribution
;
// 延迟贡献度
BottleneckOperationAnalysis
(
GAScheduleResult
op
)
{
this
.
operation
=
op
;
this
.
bottleneckScore
=
0
;
this
.
waitTime
=
0
;
this
.
machineWaitTime
=
0
;
this
.
onCriticalPath
=
false
;
this
.
delayContribution
=
0
;
}
}
/**
* 记录瓶颈分析详情(增强版)
*/
private
void
logBottleneckAnalysis
(
Map
<
String
,
Object
>
analysis
)
{
StringBuilder
sb
=
new
StringBuilder
(
"变邻域搜索 - 瓶颈分析: "
);
Long
bottleneckMachineId
=
(
Long
)
analysis
.
get
(
"bottleneckMachineId"
);
List
<
GAScheduleResult
>
criticalOps
=
(
List
<
GAScheduleResult
>)
analysis
.
get
(
"criticalOps"
);
List
<
GAScheduleResult
>
delayedOps
=
(
List
<
GAScheduleResult
>)
analysis
.
get
(
"delayedOps"
);
Map
<
Long
,
Double
>
utilization
=
(
Map
<
Long
,
Double
>)
analysis
.
get
(
"utilization"
);
List
<
GAScheduleResult
>
allResults
=
(
List
<
GAScheduleResult
>)
analysis
.
get
(
"allResults"
);
sb
.
append
(
String
.
format
(
"瓶颈设备ID=%d, "
,
bottleneckMachineId
));
sb
.
append
(
String
.
format
(
"关键工序数=%d, "
,
criticalOps
!=
null
?
criticalOps
.
size
()
:
0
));
sb
.
append
(
String
.
format
(
"延迟工序数=%d, "
,
delayedOps
!=
null
?
delayedOps
.
size
()
:
0
));
if
(
utilization
!=
null
&&
!
utilization
.
isEmpty
())
{
sb
.
append
(
"设备利用率: "
);
utilization
.
entrySet
().
stream
()
.
sorted
(
Map
.
Entry
.<
Long
,
Double
>
comparingByValue
().
reversed
())
.
limit
(
5
)
.
forEach
(
e
->
sb
.
append
(
String
.
format
(
"[%d:%.1f%%] "
,
e
.
getKey
(),
e
.
getValue
()
*
100
)));
}
log
(
sb
.
toString
());
// 新增:精准瓶颈工序分析
if
(
allResults
!=
null
&&
!
allResults
.
isEmpty
())
{
List
<
BottleneckOperationAnalysis
>
bottleneckAnalyses
=
analyzeBottleneckOperations
(
allResults
,
bottleneckMachineId
);
// 输出瓶颈工序TOP 5
log
(
"变邻域搜索 - ===== 瓶颈工序TOP 5 (按瓶颈评分) ====="
);
for
(
int
i
=
0
;
i
<
Math
.
min
(
5
,
bottleneckAnalyses
.
size
());
i
++)
{
BottleneckOperationAnalysis
boa
=
bottleneckAnalyses
.
get
(
i
);
GAScheduleResult
op
=
boa
.
operation
;
log
(
String
.
format
(
" TOP%d: [工单%d-工序%d(设备%d)] | 评分=%.2f | 等待=%ds | 设备等待=%ds | 关键路径=%s | 延迟贡献=%.2f"
,
i
+
1
,
op
.
getGroupId
(),
op
.
getOperationId
(),
op
.
getMachineId
(),
boa
.
bottleneckScore
,
boa
.
waitTime
,
boa
.
machineWaitTime
,
boa
.
onCriticalPath
?
"是"
:
"否"
,
boa
.
delayContribution
));
}
// 更新关键工序为识别出的瓶颈工序
if
(
criticalOps
!=
null
&&
!
criticalOps
.
isEmpty
()
&&
!
bottleneckAnalyses
.
isEmpty
())
{
List
<
GAScheduleResult
>
topBottlenecks
=
bottleneckAnalyses
.
stream
()
.
limit
(
Math
.
min
(
10
,
bottleneckAnalyses
.
size
()))
.
map
(
boa
->
boa
.
operation
)
.
collect
(
Collectors
.
toList
());
analysis
.
put
(
"criticalOps"
,
topBottlenecks
);
}
}
// 默认策略:随机邻域
return
generateRandomNeighbor
(
chromosome
,
entrys
);
// 记录原始关键工序详情(前5个)作为参考
if
(
criticalOps
!=
null
&&
!
criticalOps
.
isEmpty
())
{
StringBuilder
criticalOpsSb
=
new
StringBuilder
(
"变邻域搜索 - 原始关键工序(前5个): "
);
criticalOps
.
stream
()
.
limit
(
5
)
.
forEach
(
op
->
criticalOpsSb
.
append
(
String
.
format
(
"[工单%d-工序%d(设备%d)] "
,
op
.
getGroupId
(),
op
.
getOperationId
(),
op
.
getMachineId
())));
log
(
criticalOpsSb
.
toString
());
}
}
/**
* 精准分析瓶颈工序
*/
private
List
<
BottleneckOperationAnalysis
>
analyzeBottleneckOperations
(
List
<
GAScheduleResult
>
allResults
,
Long
bottleneckMachineId
)
{
if
(
allResults
==
null
||
allResults
.
isEmpty
())
{
return
new
ArrayList
<>();
}
// 1. 按工单和工序顺序组织数据
Map
<
Integer
,
List
<
GAScheduleResult
>>
opsByGroup
=
allResults
.
stream
()
.
collect
(
Collectors
.
groupingBy
(
GAScheduleResult:
:
getGroupId
));
Map
<
Long
,
List
<
GAScheduleResult
>>
opsByMachine
=
allResults
.
stream
()
.
collect
(
Collectors
.
groupingBy
(
GAScheduleResult:
:
getMachineId
));
// 2. 计算每个订单的完成时间
Map
<
Integer
,
Integer
>
orderCompletionTime
=
new
HashMap
<>();
for
(
List
<
GAScheduleResult
>
ops
:
opsByGroup
.
values
())
{
int
maxEndTime
=
ops
.
stream
()
.
mapToInt
(
GAScheduleResult:
:
getEndTime
)
.
max
()
.
orElse
(
0
);
for
(
GAScheduleResult
op
:
ops
)
{
orderCompletionTime
.
put
(
op
.
getGroupId
(),
maxEndTime
);
}
}
// 3. 创建分析对象
List
<
BottleneckOperationAnalysis
>
analyses
=
new
ArrayList
<>();
Map
<
Integer
,
BottleneckOperationAnalysis
>
opIdToAnalysis
=
new
HashMap
<>();
for
(
GAScheduleResult
op
:
allResults
)
{
BottleneckOperationAnalysis
boa
=
new
BottleneckOperationAnalysis
(
op
);
analyses
.
add
(
boa
);
opIdToAnalysis
.
put
(
op
.
getOperationId
(),
boa
);
}
// 4. 计算工序等待时间(同一工单内,前一工序结束到本工序开始)
for
(
List
<
GAScheduleResult
>
ops
:
opsByGroup
.
values
())
{
ops
.
sort
(
Comparator
.
comparingInt
(
GAScheduleResult:
:
getStartTime
));
for
(
int
i
=
1
;
i
<
ops
.
size
();
i
++)
{
GAScheduleResult
prevOp
=
ops
.
get
(
i
-
1
);
GAScheduleResult
currOp
=
ops
.
get
(
i
);
BottleneckOperationAnalysis
boa
=
opIdToAnalysis
.
get
(
currOp
.
getOperationId
());
if
(
boa
!=
null
)
{
boa
.
waitTime
=
Math
.
max
(
0
,
currOp
.
getStartTime
()
-
prevOp
.
getEndTime
());
}
}
}
// 5. 计算设备等待时间(同一设备上,前一工序结束到本工序开始)
for
(
List
<
GAScheduleResult
>
ops
:
opsByMachine
.
values
())
{
ops
.
sort
(
Comparator
.
comparingInt
(
GAScheduleResult:
:
getStartTime
));
for
(
int
i
=
1
;
i
<
ops
.
size
();
i
++)
{
GAScheduleResult
prevOp
=
ops
.
get
(
i
-
1
);
GAScheduleResult
currOp
=
ops
.
get
(
i
);
BottleneckOperationAnalysis
boa
=
opIdToAnalysis
.
get
(
currOp
.
getOperationId
());
if
(
boa
!=
null
)
{
boa
.
machineWaitTime
=
Math
.
max
(
0
,
currOp
.
getStartTime
()
-
prevOp
.
getEndTime
());
}
}
}
// 6. 识别关键路径(从后往前推,没有松弛时间的工序)
int
maxMakespan
=
allResults
.
stream
()
.
mapToInt
(
GAScheduleResult:
:
getEndTime
)
.
max
()
.
orElse
(
0
);
// 按结束时间倒序排列
List
<
GAScheduleResult
>
sortedByEndTime
=
new
ArrayList
<>(
allResults
);
sortedByEndTime
.
sort
((
a
,
b
)
->
Integer
.
compare
(
b
.
getEndTime
(),
a
.
getEndTime
()));
// 找出在最大完工时间的工序作为关键路径起点
for
(
GAScheduleResult
op
:
sortedByEndTime
)
{
if
(
op
.
getEndTime
()
==
maxMakespan
)
{
BottleneckOperationAnalysis
boa
=
opIdToAnalysis
.
get
(
op
.
getOperationId
());
if
(
boa
!=
null
)
{
boa
.
onCriticalPath
=
true
;
}
}
}
// 7. 计算延迟贡献度(工序结束时间与订单完成时间的接近程度)
double
avgCompletionTime
=
orderCompletionTime
.
values
().
stream
()
.
mapToInt
(
Integer:
:
intValue
)
.
average
()
.
orElse
(
1
);
for
(
BottleneckOperationAnalysis
boa
:
analyses
)
{
GAScheduleResult
op
=
boa
.
operation
;
Integer
orderEndTime
=
orderCompletionTime
.
get
(
op
.
getGroupId
());
if
(
orderEndTime
!=
null
&&
orderEndTime
>
0
)
{
// 工序越接近订单完成时间,延迟贡献度越高
boa
.
delayContribution
=
(
double
)
op
.
getEndTime
()
/
orderEndTime
;
}
}
// 8. 计算综合瓶颈评分 - 修复版(防数据偏倚)
// 使用中位数和截断来避免极端值影响(如设备2341有2000多工序的情况)
List
<
Integer
>
waitTimes
=
analyses
.
stream
().
mapToInt
(
a
->
a
.
waitTime
).
boxed
().
collect
(
Collectors
.
toList
());
List
<
Integer
>
machineWaitTimes
=
analyses
.
stream
().
mapToInt
(
a
->
a
.
machineWaitTime
).
boxed
().
collect
(
Collectors
.
toList
());
Collections
.
sort
(
waitTimes
);
Collections
.
sort
(
machineWaitTimes
);
// 使用90分位数代替最大值,避免极端值影响
double
p90WaitTime
=
Math
.
max
(
1
,
getPercentile
(
waitTimes
,
0.90
));
// 防止0导致NaN
double
p90MachineWaitTime
=
Math
.
max
(
1
,
getPercentile
(
machineWaitTimes
,
0.90
));
// 防止0导致NaN
// 优先找出瓶颈设备上的工序
List
<
BottleneckOperationAnalysis
>
bottleneckMachineOps
=
new
ArrayList
<>();
if
(
bottleneckMachineId
!=
null
)
{
for
(
BottleneckOperationAnalysis
boa
:
analyses
)
{
if
(
boa
.
operation
.
getMachineId
()
==
bottleneckMachineId
)
{
bottleneckMachineOps
.
add
(
boa
);
}
}
}
// 统计各设备的工序数量,用于后续分析
Map
<
Long
,
Long
>
machineOpCount
=
analyses
.
stream
()
.
collect
(
Collectors
.
groupingBy
(
a
->
a
.
operation
.
getMachineId
(),
Collectors
.
counting
()));
for
(
BottleneckOperationAnalysis
boa
:
analyses
)
{
double
score
=
0
;
boolean
isOnBottleneckMachine
=
(
bottleneckMachineId
!=
null
&&
boa
.
operation
.
getMachineId
()
==
bottleneckMachineId
);
if
(
isOnBottleneckMachine
)
{
// 瓶颈设备上的工序:基础分极高,确保排在最前面
score
+=
10000
;
// 提高到10000,绝对保证排在前面
// 在瓶颈设备工序内部进行排序(使用截断值)
// 工序等待时间 (权重 30%)
double
normalizedWaitTime
=
Math
.
min
(
boa
.
waitTime
/
p90WaitTime
,
1.5
);
score
+=
normalizedWaitTime
*
30
;
// 设备等待时间 (权重 30%)
double
normalizedMachineWaitTime
=
Math
.
min
(
boa
.
machineWaitTime
/
p90MachineWaitTime
,
1.5
);
score
+=
normalizedMachineWaitTime
*
30
;
// 关键路径评分 (权重 25%)
if
(
boa
.
onCriticalPath
)
{
score
+=
25
;
}
// 延迟贡献度评分 (权重 15%)
score
+=
boa
.
delayContribution
*
15
;
}
else
{
// 非瓶颈设备上的工序:基础分低
score
+=
0
;
// 使用截断值,避免极端值影响
double
normalizedMachineWaitTime
=
Math
.
min
(
boa
.
machineWaitTime
/
p90MachineWaitTime
,
1.5
);
score
+=
normalizedMachineWaitTime
*
30
;
double
normalizedWaitTime
=
Math
.
min
(
boa
.
waitTime
/
p90WaitTime
,
1.5
);
score
+=
normalizedWaitTime
*
20
;
// 关键路径评分 (权重 20%)
if
(
boa
.
onCriticalPath
)
{
score
+=
20
;
}
// 延迟贡献度评分 (权重 10%)
score
+=
boa
.
delayContribution
*
10
;
}
boa
.
bottleneckScore
=
score
;
}
// 记录修复后的瓶颈工序信息
log
(
String
.
format
(
"变邻域搜索 - 瓶颈设备ID=%d, 其上工序数=%d"
,
bottleneckMachineId
,
bottleneckMachineOps
.
size
()));
// 输出各设备工序数量统计(前5个)
List
<
Map
.
Entry
<
Long
,
Long
>>
topMachinesByCount
=
machineOpCount
.
entrySet
().
stream
()
.
sorted
((
a
,
b
)
->
Long
.
compare
(
b
.
getValue
(),
a
.
getValue
()))
.
limit
(
5
)
.
collect
(
Collectors
.
toList
());
StringBuilder
machineCountStr
=
new
StringBuilder
(
"变邻域搜索 - 设备工序数(前5): "
);
for
(
Map
.
Entry
<
Long
,
Long
>
entry
:
topMachinesByCount
)
{
machineCountStr
.
append
(
String
.
format
(
"[%d:%d] "
,
entry
.
getKey
(),
entry
.
getValue
()));
}
log
(
machineCountStr
.
toString
());
// 9. 按瓶颈评分排序
analyses
.
sort
((
a
,
b
)
->
Double
.
compare
(
b
.
bottleneckScore
,
a
.
bottleneckScore
));
return
analyses
;
}
/**
* 计算百分位数(用于防数据偏倚)
*/
private
double
getPercentile
(
List
<
Integer
>
sortedValues
,
double
percentile
)
{
if
(
sortedValues
.
isEmpty
())
{
return
1
;
}
int
index
=
(
int
)
Math
.
ceil
(
percentile
*
sortedValues
.
size
())
-
1
;
index
=
Math
.
max
(
0
,
Math
.
min
(
index
,
sortedValues
.
size
()
-
1
));
return
sortedValues
.
get
(
index
);
}
/**
* 构建策略顺序,基于成功率动态调整(优化版 + 强制轮换)
*/
private
List
<
Integer
>
buildStrategyOrder
()
{
List
<
Integer
>
strategies
=
new
ArrayList
<>(
Arrays
.
asList
(
0
,
1
,
2
,
3
));
// 强制策略轮换:如果某个策略被连续使用超过 MAX_CONSECUTIVE_SAME_STRATEGY 次,强制换一个
boolean
needForceRotate
=
(
lastUsedStrategy
>=
0
&&
consecutiveSameStrategyCount
>=
MAX_CONSECUTIVE_SAME_STRATEGY
);
if
(
needForceRotate
)
{
log
(
String
.
format
(
"强制策略轮换:策略%d已连续使用%d次"
,
lastUsedStrategy
,
consecutiveSameStrategyCount
));
}
// 按成功率排序,但加入随机扰动和探索机制
strategies
.
sort
((
a
,
b
)
->
{
double
successRateA
=
strategyTotalCount
[
a
]
>
0
?
(
double
)
strategySuccessCount
[
a
]
/
strategyTotalCount
[
a
]
:
0.3
;
double
successRateB
=
strategyTotalCount
[
b
]
>
0
?
(
double
)
strategySuccessCount
[
b
]
/
strategyTotalCount
[
b
]
:
0.3
;
// 强制轮换:给最后使用的策略降权
if
(
needForceRotate
&&
a
==
lastUsedStrategy
)
{
successRateA
-=
0.5
;
// 大幅降权
}
if
(
needForceRotate
&&
b
==
lastUsedStrategy
)
{
successRateB
-=
0.5
;
}
// 给使用次数少的策略加分,鼓励探索
if
(
strategyTotalCount
[
a
]
<
5
)
{
successRateA
+=
0.3
;
}
if
(
strategyTotalCount
[
b
]
<
5
)
{
successRateB
+=
0.3
;
}
// 如果策略被尝试次数很多但成功率很低,给它额外加分鼓励探索
if
(
strategyTotalCount
[
a
]
>
10
&&
successRateA
<
0.1
)
{
successRateA
+=
0.2
;
}
if
(
strategyTotalCount
[
b
]
>
10
&&
successRateB
<
0.1
)
{
successRateB
+=
0.2
;
}
// 加入少量随机扰动,避免陷入局部最优
successRateA
+=
rnd
.
nextDouble
()
*
0.15
;
successRateB
+=
rnd
.
nextDouble
()
*
0.15
;
return
Double
.
compare
(
successRateB
,
successRateA
);
});
return
strategies
;
}
/**
* 记录策略统计信息
*/
private
void
logStrategyStats
()
{
StringBuilder
sb
=
new
StringBuilder
(
"策略统计: "
);
for
(
int
i
=
0
;
i
<
4
;
i
++)
{
double
rate
=
strategyTotalCount
[
i
]
>
0
?
(
double
)
strategySuccessCount
[
i
]
/
strategyTotalCount
[
i
]
:
0.0
;
sb
.
append
(
String
.
format
(
"[%d]%d/%d(%.1f%%) "
,
i
+
1
,
strategySuccessCount
[
i
],
strategyTotalCount
[
i
],
rate
*
100
));
}
log
(
sb
.
toString
());
}
/**
* 识别瓶颈设备(利用率最高的设备)
...
...
@@ -218,8 +1026,7 @@ public class VariableNeighborhoodSearch {
/**
* 尝试给瓶颈设备上的工序换设备
*/
private
Chromosome
tryChangeMachineForBottleneckOp
(
Chromosome
chromosome
,
List
<
GAScheduleResult
>
bottleneckOps
,
Map
<
String
,
Entry
>
entrys
,
Map
<
String
,
Integer
>
MachinePositionIndex
)
{
// 优先选择有多设备选项的工序
private
Chromosome
tryChangeMachineForBottleneckOp
(
Chromosome
chromosome
,
List
<
GAScheduleResult
>
bottleneckOps
,
Map
<
String
,
Integer
>
MachinePositionIndex
,
Map
<
Integer
,
Entry
>
positionIndex
,
List
<
List
<
Integer
>>
positionByPriority
)
{
List
<
GAScheduleResult
>
candidates
=
bottleneckOps
.
stream
()
.
filter
(
op
->
{
Entry
entry
=
entrybyids
.
get
(
op
.
getOperationId
());
...
...
@@ -227,31 +1034,107 @@ public class VariableNeighborhoodSearch {
})
.
collect
(
Collectors
.
toList
());
log
(
String
.
format
(
"tryChangeMachineForBottleneckOp: 候选工序数=%d (瓶颈工序总数=%d)"
,
candidates
.
size
(),
bottleneckOps
.
size
()));
if
(
candidates
.
isEmpty
())
{
return
generateRandomNeighbor
(
chromosome
,
entrys
);
log
(
"tryChangeMachineForBottleneckOp: 没有可换设备的候选工序"
);
return
null
;
}
// 优先选择订单数多的优先级的工序
// 构建优先级->订单数的映射
Map
<
Double
,
Set
<
Integer
>>
priorityToGroupIds
=
new
HashMap
<>();
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
());
}
}
// 从候选中随机选择一个工序,给它换设备
GAScheduleResult
selectedOp
=
candidates
.
get
(
rnd
.
nextInt
(
candidates
.
size
()));
// 按订单数从多到少排序候选工序
List
<
GAScheduleResult
>
sortedCandidates
=
new
ArrayList
<>(
candidates
);
sortedCandidates
.
sort
((
a
,
b
)
->
{
Entry
entryA
=
entrybyids
.
get
(
a
.
getOperationId
());
Entry
entryB
=
entrybyids
.
get
(
b
.
getOperationId
());
if
(
entryA
==
null
||
entryB
==
null
)
{
return
0
;
}
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
;
}
// 订单数相同时,按优先级排序
return
Double
.
compare
(
entryB
.
getPriority
(),
entryA
.
getPriority
());
});
// 70%概率选择前3个候选,30%概率随机选择
GAScheduleResult
selectedOp
;
if
(
sortedCandidates
.
size
()
<=
3
)
{
selectedOp
=
sortedCandidates
.
get
(
rnd
.
nextInt
(
sortedCandidates
.
size
()));
}
else
{
if
(
rnd
.
nextDouble
()
<
0.7
)
{
selectedOp
=
sortedCandidates
.
get
(
rnd
.
nextInt
(
Math
.
min
(
3
,
sortedCandidates
.
size
())));
}
else
{
selectedOp
=
sortedCandidates
.
get
(
3
+
rnd
.
nextInt
(
sortedCandidates
.
size
()
-
3
));
}
}
// 找到这个工序在globalOpList中的位置
int
maPos
=
-
1
;
Entry
entry
=
entrybyids
.
get
(
selectedOp
.
getOperationId
());
if
(
entry
!=
null
&&
entry
.
getMachineOptions
().
size
()
>
1
)
{
maPos
=
MachinePositionIndex
.
get
(
entry
.
getGroupId
()
+
"_"
+
entry
.
getSequence
());
if
(
maPos
>=
0
)
{
log
(
"tryChangeMachineForBottleneckOp: 成功找到工序,执行换设备"
);
return
generateMachineChangeForSpecificOp
(
chromosome
,
entry
.
getMachineOptions
(),
maPos
);
}
}
// 直接换设备
return
generateMachineChangeNeighbor
(
chromosome
);
log
(
"tryChangeMachineForBottleneckOp: 找不到工序位置,尝试通用换设备"
);
Chromosome
result
=
generateMachineChangeNeighbor
(
chromosome
);
return
result
!=
null
?
result
:
null
;
}
private
Chromosome
ChangeMachineForBottleneckOpWrapper
(
Chromosome
chromosome
)
{
List
<
GAScheduleResult
>
results
=
chromosome
.
getResult
();
Map
<
Integer
,
Object
>
obj
=
buildPositionToEntryIndex
(
chromosome
);
Map
<
Integer
,
Entry
>
positionToEntryIndex
=
(
Map
<
Integer
,
Entry
>)
obj
.
get
(
1
);
List
<
List
<
Integer
>>
positionByPriority
=
(
List
<
List
<
Integer
>>)
obj
.
get
(
2
);
if
(
results
==
null
||
results
.
isEmpty
())
{
return
generateRandomNeighbor
(
chromosome
,
positionToEntryIndex
,
positionByPriority
);
}
Map
<
String
,
Integer
>
machinePositionIndex
=
buildEntryMachinePositionIndex
(
chromosome
);
Long
bottleneckMachineId
=
findBottleneckMachine
(
chromosome
);
if
(
bottleneckMachineId
!=
null
)
{
List
<
GAScheduleResult
>
bottleneckOps
=
findOpsOnBottleneckMachine
(
chromosome
,
bottleneckMachineId
);
if
(!
bottleneckOps
.
isEmpty
())
{
Chromosome
result
=
tryChangeMachineForBottleneckOp
(
chromosome
,
bottleneckOps
,
machinePositionIndex
,
positionToEntryIndex
,
positionByPriority
);
if
(
result
!=
null
)
{
return
result
;
}
}
}
return
generateRandomNeighbor
(
chromosome
,
positionToEntryIndex
,
positionByPriority
);
}
/**
* 给指定位置的工序换设备
*/
private
Chromosome
generateMachineChangeForSpecificOp
(
Chromosome
chromosome
,
List
<
MachineOption
>
machineOptions
,
int
idx
)
{
Chromosome
neighbor
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
Chromosome
neighbor
=
copyChromosome
(
chromosome
);
//
ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class);
List
<
Integer
>
ms
=
neighbor
.
getMachineSelection
();
if
(!
ms
.
isEmpty
()
&&
idx
>=
0
&&
idx
<
ms
.
size
())
{
if
(
machineOptions
.
size
()
>
1
)
{
...
...
@@ -273,65 +1156,143 @@ public class VariableNeighborhoodSearch {
return
neighbor
;
}
private
Chromosome
moveBottleneckForwardWrapper
(
Chromosome
chromosome
)
{
List
<
GAScheduleResult
>
results
=
chromosome
.
getResult
();
Map
<
String
,
Integer
>
positionIndex
=
buildPositionIndex
(
chromosome
);
Map
<
Integer
,
Object
>
obj
=
buildPositionToEntryIndex
(
chromosome
);
Map
<
Integer
,
Entry
>
positionToEntryIndex
=(
Map
<
Integer
,
Entry
>)
obj
.
get
(
1
);
List
<
List
<
Integer
>>
positionByPriority
=
(
List
<
List
<
Integer
>>)
obj
.
get
(
2
);
Map
<
String
,
Integer
>
MachinePositionIndex
=
buildEntryMachinePositionIndex
(
chromosome
);
if
(
results
==
null
||
results
.
isEmpty
())
{
return
generateRandomNeighbor
(
chromosome
,
positionToEntryIndex
,
positionByPriority
);
}
Long
bottleneckMachineId
=
findBottleneckMachine
(
chromosome
);
if
(
bottleneckMachineId
!=
null
)
{
List
<
GAScheduleResult
>
bottleneckOps
=
findOpsOnBottleneckMachine
(
chromosome
,
bottleneckMachineId
);
if
(!
bottleneckOps
.
isEmpty
())
{
Chromosome
result
=
tryMoveBottleneckOpForward
(
chromosome
,
bottleneckOps
,
positionIndex
,
positionByPriority
,
positionToEntryIndex
,
MachinePositionIndex
,
false
);
if
(
result
!=
null
)
{
return
result
;
}
}
}
return
generateRandomNeighbor
(
chromosome
,
positionToEntryIndex
,
positionByPriority
);
}
private
Chromosome
moveBottleneckSameMachineWrapper
(
Chromosome
chromosome
)
{
List
<
GAScheduleResult
>
results
=
chromosome
.
getResult
();
Map
<
String
,
Integer
>
positionIndex
=
buildPositionIndex
(
chromosome
);
Map
<
Integer
,
Object
>
obj
=
buildPositionToEntryIndex
(
chromosome
);
Map
<
Integer
,
Entry
>
positionToEntryIndex
=(
Map
<
Integer
,
Entry
>)
obj
.
get
(
1
);
List
<
List
<
Integer
>>
positionByPriority
=
(
List
<
List
<
Integer
>>)
obj
.
get
(
2
);
Map
<
String
,
Integer
>
MachinePositionIndex
=
buildEntryMachinePositionIndex
(
chromosome
);
if
(
results
==
null
||
results
.
isEmpty
())
{
return
generateRandomNeighbor
(
chromosome
,
positionToEntryIndex
,
positionByPriority
);
}
Long
bottleneckMachineId
=
findBottleneckMachine
(
chromosome
);
if
(
bottleneckMachineId
!=
null
)
{
List
<
GAScheduleResult
>
bottleneckOps
=
findOpsOnBottleneckMachine
(
chromosome
,
bottleneckMachineId
);
if
(!
bottleneckOps
.
isEmpty
())
{
Chromosome
result
=
tryMoveBottleneckOpForward
(
chromosome
,
bottleneckOps
,
positionIndex
,
positionByPriority
,
positionToEntryIndex
,
MachinePositionIndex
,
true
);
if
(
result
!=
null
)
{
return
result
;
}
}
}
return
generateRandomNeighbor
(
chromosome
,
positionToEntryIndex
,
positionByPriority
);
}
/**
* 尝试将瓶颈设备上的工序往前移动
*/
private
Chromosome
tryMoveBottleneckOpForward
(
Chromosome
chromosome
,
List
<
GAScheduleResult
>
bottleneckOps
,
Map
<
String
,
Integer
>
position
Index
,
Map
<
Integer
,
Entry
>
positionToEntryIndex
,
Map
<
String
,
Entry
>
entrys
)
{
Map
<
String
,
Integer
>
position
key
,
List
<
List
<
Integer
>>
positionByPriority
,
Map
<
Integer
,
Entry
>
positionIndex
,
Map
<
String
,
Integer
>
machinePositionIndex
,
boolean
isSameMachine
)
{
log
(
String
.
format
(
"tryMoveBottleneckOpForward: isSameMachine=%b"
,
isSameMachine
));
if
(
bottleneckOps
.
isEmpty
())
{
return
generateSwapNeighbor
(
chromosome
,
entrys
);
log
(
"tryMoveBottleneckOpForward: 瓶颈工序为空"
);
return
null
;
}
// 随机选择一个瓶颈工序
// GAScheduleResult randomOp = bottleneckOps.get(rnd.nextInt(bottleneckOps.size()));
// 计算所有订单的完成时间
List
<
GAScheduleResult
>
allResults
=
chromosome
.
getResult
();
Map
<
Integer
,
Integer
>
orderCompletionTimes
=
calculateOrderCompletionTimes
(
allResults
);
// 找出最晚完成的订单(延期候选)
int
latestCompletionTime
=
orderCompletionTimes
.
values
().
stream
()
.
mapToInt
(
Integer:
:
intValue
)
.
max
()
.
orElse
(
0
);
// 先构建优先级->订单数的映射
Map
<
Double
,
Set
<
Integer
>>
priorityToGroupIds
=
new
HashMap
<>();
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
());
}
}
// 按优先级和订单完成时间排序:优先选择高优先级+延期订单的工序
List
<
GAScheduleResult
>
sortedBottleneckOps
=
new
ArrayList
<>(
bottleneckOps
);
sortedBottleneckOps
.
sort
((
a
,
b
)
->
{
Entry
entryA
=
entrybyids
.
get
(
a
.
getOperationId
());
Entry
entryB
=
entrybyids
.
get
(
b
.
getOperationId
());
if
(
entryA
!=
null
&&
entryB
!=
null
)
{
// 首先比较优先级(高优先级在前)
// 优先按订单数从多到少排序
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
;
}
// 订单数相同时,按优先级排序
int
priorityCompare
=
Double
.
compare
(
entryB
.
getPriority
(),
entryA
.
getPriority
());
if
(
priorityCompare
!=
0
)
{
return
priorityCompare
;
}
// 优先级相同
,比较订单完成时间(晚完成的在前,即更可能延期)
// 优先级相同
时,按完成时间排序
int
endTimeA
=
orderCompletionTimes
.
getOrDefault
(
a
.
getGroupId
(),
0
);
int
endTimeB
=
orderCompletionTimes
.
getOrDefault
(
b
.
getGroupId
(),
0
);
return
Integer
.
compare
(
endTimeB
,
endTimeA
);
}
return
0
;
});
if
(
sortedBottleneckOps
.
isEmpty
())
{
log
(
"tryMoveBottleneckOpForward: 排序后为空"
);
return
null
;
}
GAScheduleResult
selectedOp
=
sortedBottleneckOps
.
get
(
rnd
.
nextInt
(
Math
.
min
(
5
,
sortedBottleneckOps
.
size
())));
Entry
entry
=
entrybyids
.
get
(
selectedOp
.
getOperationId
())
;
Entry
entry
=
entrybyids
.
get
(
selectedOp
.
getOperationId
());
if
(
entry
==
null
)
{
log
(
"tryMoveBottleneckOpForward: 找不到工序"
);
return
null
;
}
String
key
=
entry
.
getGroupId
()
+
"_"
+
entry
.
getSequence
();
Integer
opPos
=
position
Index
.
get
(
key
);
Integer
opPos
=
position
key
.
get
(
key
);
if
(
opPos
==
null
||
opPos
<=
0
)
{
return
generateSwapNeighbor
(
chromosome
,
entrys
);
log
(
"tryMoveBottleneckOpForward: 找不到工序位置"
);
return
null
;
}
// 往前移动1-3步
// int steps = rnd.nextInt(3) + 1;
// return moveOperationForward(chromosome,positionToEntryIndex, opPos, steps);
// 使用插入方式往前移动(1-5步)
log
(
String
.
format
(
"tryMoveBottleneckOpForward: 找到工序位置=%d"
,
opPos
));
if
(
isSameMachine
)
{
Chromosome
result
=
generateSameMachineSwapNeighbor
(
chromosome
,
opPos
,
positionIndex
,
machinePositionIndex
);
log
(
"tryMoveBottleneckOpForward: 相同设备交换完成"
);
return
result
;
}
else
{
int
steps
=
rnd
.
nextInt
(
5
)
+
1
;
return
insertOperationForward
(
chromosome
,
opPos
,
steps
,
entrys
);
Chromosome
result
=
insertOperationForward
(
chromosome
,
opPos
,
steps
,
entrys
,
positionIndex
);
log
(
String
.
format
(
"tryMoveBottleneckOpForward: 往前插入%d步完成"
,
steps
));
return
result
;
}
}
/**
* 计算每个订单的最后完成时间
...
...
@@ -345,40 +1306,76 @@ public class VariableNeighborhoodSearch {
}
return
orderEndTimes
;
}
private
Chromosome
moveNonBottleneckBackwardWrapper
(
Chromosome
chromosome
)
{
List
<
GAScheduleResult
>
results
=
chromosome
.
getResult
();
Map
<
String
,
Integer
>
positionIndex
=
buildPositionIndex
(
chromosome
);
Map
<
Integer
,
Object
>
obj
=
buildPositionToEntryIndex
(
chromosome
);
Map
<
Integer
,
Entry
>
positionToEntryIndex
=(
Map
<
Integer
,
Entry
>)
obj
.
get
(
1
);
List
<
List
<
Integer
>>
positionByPriority
=
(
List
<
List
<
Integer
>>)
obj
.
get
(
2
);
if
(
results
==
null
||
results
.
isEmpty
())
{
return
generateRandomNeighbor
(
chromosome
,
positionToEntryIndex
,
positionByPriority
);
}
Long
bottleneckMachineId
=
findBottleneckMachine
(
chromosome
);
if
(
bottleneckMachineId
!=
null
)
{
Chromosome
result
=
tryMoveNonBottleneckOpBackward
(
chromosome
,
bottleneckMachineId
,
positionIndex
,
positionByPriority
,
positionToEntryIndex
);
if
(
result
!=
null
)
{
return
result
;
}
}
return
generateRandomNeighbor
(
chromosome
,
positionToEntryIndex
,
positionByPriority
);
}
/**
* 尝试将非瓶颈设备上的工序往后移动(给瓶颈工序腾位置)
*/
private
Chromosome
tryMoveNonBottleneckOpBackward
(
Chromosome
chromosome
,
Long
bottleneckMachineId
,
Map
<
String
,
Integer
>
positionIndex
,
Map
<
Integer
,
Entry
>
positionToEntryIndex
,
Map
<
String
,
Entry
>
entrys
)
{
Map
<
String
,
Integer
>
positionIndex
,
List
<
List
<
Integer
>>
positionByPriority
,
Map
<
Integer
,
Entry
>
positionToEntryIndex
)
{
log
(
String
.
format
(
"tryMoveNonBottleneckOpBackward: 瓶颈设备ID=%d"
,
bottleneckMachineId
));
List
<
GAScheduleResult
>
results
=
chromosome
.
getResult
();
if
(
results
==
null
)
{
return
generateSwapNeighbor
(
chromosome
,
entrys
);
log
(
"tryMoveNonBottleneckOpBackward: results为空"
);
return
null
;
}
// 找出非瓶颈设备上的工序
List
<
GAScheduleResult
>
nonBottleneckOps
=
results
.
stream
()
.
filter
(
r
->
r
.
getMachineId
()
!=
bottleneckMachineId
)
.
filter
(
r
->
r
.
getMachineId
()
!=(
bottleneckMachineId
)
)
.
collect
(
Collectors
.
toList
());
log
(
String
.
format
(
"tryMoveNonBottleneckOpBackward: 非瓶颈工序数=%d"
,
nonBottleneckOps
.
size
()));
if
(
nonBottleneckOps
.
isEmpty
())
{
return
generateSwapNeighbor
(
chromosome
,
entrys
);
log
(
"tryMoveNonBottleneckOpBackward: 没有非瓶颈工序"
);
return
null
;
}
// 随机选择一个非瓶颈工序
GAScheduleResult
randomOp
=
nonBottleneckOps
.
get
(
rnd
.
nextInt
(
nonBottleneckOps
.
size
()));
Entry
entry
=
entrybyids
.
get
(
randomOp
.
getOperationId
());
String
key
=
entry
.
getGroupId
()+
"_"
+
entry
.
getSequence
();
Entry
entry
=
entrybyids
.
get
(
randomOp
.
getOperationId
());
if
(
entry
==
null
)
{
log
(
"tryMoveNonBottleneckOpBackward: 找不到工序"
);
return
null
;
}
String
key
=
entry
.
getGroupId
()
+
"_"
+
entry
.
getSequence
();
Integer
opPos
=
positionIndex
.
get
(
key
);
if
(
opPos
==
null
||
opPos
>=
chromosome
.
getOperationSequencing
().
size
()
-
1
)
{
return
generateSwapNeighbor
(
chromosome
,
entrys
);
log
(
"tryMoveNonBottleneckOpBackward: 工序位置无效"
);
return
null
;
}
// 往后移动1-3步
log
(
String
.
format
(
"tryMoveNonBottleneckOpBackward: 找到工序位置=%d"
,
opPos
));
int
steps
=
rnd
.
nextInt
(
3
)
+
1
;
return
moveOperationBackward
(
chromosome
,
positionToEntryIndex
,
opPos
,
steps
);
Chromosome
result
=
moveOperationBackward
(
chromosome
,
positionToEntryIndex
,
opPos
,
steps
);
log
(
String
.
format
(
"tryMoveNonBottleneckOpBackward: 往后移动%d步完成"
,
steps
));
return
result
;
}
/**
* 将工序往前移动
...
...
@@ -418,7 +1415,7 @@ public class VariableNeighborhoodSearch {
* 将工序往后移动
*/
private
Chromosome
moveOperationBackward
(
Chromosome
chromosome
,
Map
<
Integer
,
Entry
>
originalPositionIndex
,
int
pos
,
int
steps
)
{
Chromosome
neighbor
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
Chromosome
neighbor
=
copyChromosome
(
chromosome
);
//
ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class);
List
<
Integer
>
os
=
neighbor
.
getOperationSequencing
();
if
(
pos
<
0
||
pos
>=
os
.
size
()
-
1
)
{
...
...
@@ -452,8 +1449,8 @@ public class VariableNeighborhoodSearch {
/**
* 将工序往前插入(不交换,直接插入到目标位置)
*/
private
Chromosome
insertOperationForward
(
Chromosome
chromosome
,
int
pos
,
int
steps
,
Map
<
String
,
Entry
>
entrys
)
{
Chromosome
neighbor
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
private
Chromosome
insertOperationForward
(
Chromosome
chromosome
,
int
pos
,
int
steps
,
Map
<
String
,
Entry
>
entrys
,
Map
<
Integer
,
Entry
>
originalPositionIndex
)
{
Chromosome
neighbor
=
copyChromosome
(
chromosome
);
//
ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class);
List
<
Integer
>
os
=
neighbor
.
getOperationSequencing
();
if
(
pos
<=
0
||
pos
>=
os
.
size
())
{
...
...
@@ -461,7 +1458,7 @@ public class VariableNeighborhoodSearch {
}
// 获取要移动的工序(基于原始chromosome)
Map
<
Integer
,
Entry
>
originalPositionIndex
=
buildPositionToEntryIndex
(
chromosome
,
entrys
);
// Map<Integer, Entry> originalPositionIndex = buildPositionToEntryIndex(chromosome
);
Entry
opToMove
=
originalPositionIndex
.
get
(
pos
);
if
(
opToMove
==
null
)
{
return
neighbor
;
...
...
@@ -495,42 +1492,81 @@ public class VariableNeighborhoodSearch {
/**
* 随机生成邻域解(兜底策略)
*/
private
Chromosome
generateRandomNeighbor
(
Chromosome
chromosome
,
Map
<
String
,
Entry
>
entrys
)
{
int
neighborType
=
rnd
.
nextInt
(
4
);
private
Chromosome
generateRandomNeighbor
(
Chromosome
chromosome
,
Map
<
Integer
,
Entry
>
positionIndex
,
List
<
List
<
Integer
>>
positionByPriority
)
{
int
neighborType
=
rnd
.
nextInt
(
5
);
log
(
String
.
format
(
"随机生成邻域解-"
+
neighborType
));
switch
(
neighborType
)
{
case
0
:
return
generateSwapNeighbor
(
chromosome
,
entrys
);
return
generateSwapNeighbor
(
chromosome
,
positionIndex
,
positionByPriority
);
case
1
:
return
generateReverseNeighbor
(
chromosome
,
entrys
);
return
generateReverseNeighbor
(
chromosome
,
positionIndex
,
positionByPriority
);
case
2
:
return
generateInsertNeighbor
(
chromosome
,
entrys
);
return
generateInsertNeighbor
(
chromosome
,
positionIndex
,
positionByPriority
);
case
3
:
return
generateMachineChangeNeighbor
(
chromosome
);
case
4
:
return
generateSameMachineSwapNeighbor
(
chromosome
);
default
:
return
generateSwapNeighbor
(
chromosome
,
entrys
);
return
generateSwapNeighbor
(
chromosome
,
positionIndex
,
positionByPriority
);
}
}
private
Chromosome
generateSwapNeighborWrapper
(
Chromosome
chromosome
)
{
Map
<
Integer
,
Object
>
obj
=
buildPositionToEntryIndex
(
chromosome
);
Map
<
Integer
,
Entry
>
positionToEntryIndex
=
(
Map
<
Integer
,
Entry
>)
obj
.
get
(
1
);
List
<
List
<
Integer
>>
positionByPriority
=
(
List
<
List
<
Integer
>>)
obj
.
get
(
2
);
return
generateSwapNeighbor
(
chromosome
,
positionToEntryIndex
,
positionByPriority
);
}
private
Chromosome
copyChromosome
(
Chromosome
chromosome
)
{
Chromosome
neighbor
=
new
Chromosome
();
neighbor
.
setID
(
UUID
.
randomUUID
().
toString
());
neighbor
.
setOperationSequencing
(
chromosome
.
getOperationSequencing
());
neighbor
.
setMachineSelection
(
chromosome
.
getMachineSelection
());
neighbor
.
setScenarioID
(
chromosome
.
getScenarioID
());
neighbor
.
setBaseTime
(
chromosome
.
getBaseTime
());
neighbor
.
setFitnessLevel
(
chromosome
.
getFitnessLevel
());
neighbor
.
setGlobalOpList
(
chromosome
.
getGlobalOpList
());
return
neighbor
;
}
/**
* 生成交换邻域解 - 只在相同优先级的工序之间交换
*/
private
Chromosome
generateSwapNeighbor
(
Chromosome
chromosome
,
Map
<
String
,
Entry
>
entrys
)
{
Chromosome
neighbor
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
private
Chromosome
generateSwapNeighbor
(
Chromosome
chromosome
,
Map
<
Integer
,
Entry
>
positionIndex
,
List
<
List
<
Integer
>>
positionByPriority
)
{
Chromosome
neighbor
=
copyChromosome
(
chromosome
);
List
<
Integer
>
os
=
neighbor
.
getOperationSequencing
();
if
(
os
.
size
()
>=
2
)
{
Map
<
Integer
,
Entry
>
positionIndex
=
buildPositionToEntryIndex
(
neighbor
,
entrys
);
if
(
os
.
size
()
>=
2
&&
!
positionByPriority
.
isEmpty
())
{
int
maxAttempts
=
50
;
for
(
int
attempt
=
0
;
attempt
<
maxAttempts
;
attempt
++)
{
int
idx1
=
rnd
.
nextInt
(
os
.
size
());
int
idx2
=
rnd
.
nextInt
(
os
.
size
());
// 优先选择前面的优先级组(订单数多的),使用加权随机
int
priorityGroupIndex
;
if
(
positionByPriority
.
size
()
<=
3
)
{
priorityGroupIndex
=
rnd
.
nextInt
(
positionByPriority
.
size
());
}
else
{
// 70%概率选择前3个优先级组,30%概率选择其他
if
(
rnd
.
nextDouble
()
<
0.7
)
{
priorityGroupIndex
=
rnd
.
nextInt
(
Math
.
min
(
3
,
positionByPriority
.
size
()));
}
else
{
priorityGroupIndex
=
3
+
rnd
.
nextInt
(
positionByPriority
.
size
()
-
3
);
}
}
List
<
Integer
>
positionos
=
positionByPriority
.
get
(
priorityGroupIndex
);
if
(
positionos
.
size
()
<
2
)
continue
;
int
idx1
=
positionos
.
get
(
rnd
.
nextInt
(
positionos
.
size
()));
int
idx2
=
positionos
.
get
(
rnd
.
nextInt
(
positionos
.
size
()));
if
(
idx1
==
idx2
)
continue
;
Entry
op1
=
positionIndex
.
get
(
idx1
);
Entry
op2
=
positionIndex
.
get
(
idx2
);
if
(
op1
!=
null
&&
op2
!=
null
)
{
if
(
Math
.
abs
(
op1
.
getPriority
()
-
op2
.
getPriority
())
<
0.001
)
{
if
(
op1
.
getGroupId
()
!=
op2
.
getGroupId
()
)
{
java
.
util
.
Collections
.
swap
(
os
,
idx1
,
idx2
);
neighbor
.
setOperationSequencing
(
os
);
break
;
...
...
@@ -540,20 +1576,49 @@ public class VariableNeighborhoodSearch {
}
return
neighbor
;
}
private
Chromosome
generateReverseNeighborWrapper
(
Chromosome
chromosome
)
{
Map
<
Integer
,
Object
>
obj
=
buildPositionToEntryIndex
(
chromosome
);
Map
<
Integer
,
Entry
>
positionToEntryIndex
=
(
Map
<
Integer
,
Entry
>)
obj
.
get
(
1
);
List
<
List
<
Integer
>>
positionByPriority
=
(
List
<
List
<
Integer
>>)
obj
.
get
(
2
);
return
generateReverseNeighbor
(
chromosome
,
positionToEntryIndex
,
positionByPriority
);
}
/**
* 生成反转邻域解 - 只反转相同优先级的连续工序
*/
private
Chromosome
generateReverseNeighbor
(
Chromosome
chromosome
,
Map
<
String
,
Entry
>
entrys
)
{
Chromosome
neighbor
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
private
Chromosome
generateReverseNeighbor
(
Chromosome
chromosome
,
Map
<
Integer
,
Entry
>
positionIndex
,
List
<
List
<
Integer
>>
positionByPriority
)
{
Chromosome
neighbor
=
copyChromosome
(
chromosome
);
//
ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class);
List
<
Integer
>
os
=
neighbor
.
getOperationSequencing
();
if
(
os
.
size
()
>=
2
)
{
Map
<
Integer
,
Entry
>
positionIndex
=
buildPositionToEntryIndex
(
neighbor
,
entrys
);
// Map<Integer, Entry> positionIndex = buildPositionToEntryIndex(neighbor
);
int
maxAttempts
=
50
;
for
(
int
attempt
=
0
;
attempt
<
maxAttempts
;
attempt
++)
{
int
start
=
rnd
.
nextInt
(
os
.
size
());
int
end
=
rnd
.
nextInt
(
os
.
size
());
// 优先选择前面的优先级组(订单数多的),使用加权随机
int
priorityGroupIndex
;
if
(
positionByPriority
.
size
()
<=
3
)
{
priorityGroupIndex
=
rnd
.
nextInt
(
positionByPriority
.
size
());
}
else
{
// 70%概率选择前3个优先级组,30%概率选择其他
if
(
rnd
.
nextDouble
()
<
0.7
)
{
priorityGroupIndex
=
rnd
.
nextInt
(
Math
.
min
(
3
,
positionByPriority
.
size
()));
}
else
{
priorityGroupIndex
=
3
+
rnd
.
nextInt
(
positionByPriority
.
size
()
-
3
);
}
}
List
<
Integer
>
positionos
=
positionByPriority
.
get
(
priorityGroupIndex
);
if
(
positionos
.
size
()
<
2
)
continue
;
int
startIdxInList
=
rnd
.
nextInt
(
positionos
.
size
());
int
endIdxInList
=
rnd
.
nextInt
(
positionos
.
size
());
if
(
endIdxInList
<=
startIdxInList
)
continue
;
int
start
=
positionos
.
get
(
startIdxInList
);
int
end
=
positionos
.
get
(
endIdxInList
);
if
(
end
<=
start
)
continue
;
...
...
@@ -561,17 +1626,17 @@ public class VariableNeighborhoodSearch {
if
(
startOp
==
null
)
continue
;
double
priority
=
startOp
.
getPriority
();
boolean
allSame
Priority
=
true
;
boolean
allSame
GroupId
=
true
;
for
(
int
i
=
start
;
i
<=
end
;
i
++)
{
Entry
op
=
positionIndex
.
get
(
i
);
if
(
op
==
null
||
Math
.
abs
(
op
.
getPriority
()
-
priority
)
>
0.001
)
{
allSame
Priority
=
false
;
if
(
op
==
null
&&
op
.
getGroupId
()==
startOp
.
getGroupId
()
)
{
allSame
GroupId
=
false
;
break
;
}
}
if
(
allSame
Priority
)
{
if
(
allSame
GroupId
)
{
java
.
util
.
Collections
.
reverse
(
os
.
subList
(
start
,
end
+
1
));
neighbor
.
setOperationSequencing
(
os
);
break
;
...
...
@@ -581,19 +1646,49 @@ public class VariableNeighborhoodSearch {
return
neighbor
;
}
private
Chromosome
generateInsertNeighborWrapper
(
Chromosome
chromosome
)
{
Map
<
Integer
,
Object
>
obj
=
buildPositionToEntryIndex
(
chromosome
);
Map
<
Integer
,
Entry
>
positionToEntryIndex
=
(
Map
<
Integer
,
Entry
>)
obj
.
get
(
1
);
List
<
List
<
Integer
>>
positionByPriority
=
(
List
<
List
<
Integer
>>)
obj
.
get
(
2
);
return
generateInsertNeighbor
(
chromosome
,
positionToEntryIndex
,
positionByPriority
);
}
/**
* 生成插入邻域解 - 只插入到相同优先级的位置
*/
private
Chromosome
generateInsertNeighbor
(
Chromosome
chromosome
,
Map
<
String
,
Entry
>
entrys
)
{
Chromosome
neighbor
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
private
Chromosome
generateInsertNeighbor
(
Chromosome
chromosome
,
Map
<
Integer
,
Entry
>
positionIndex
,
List
<
List
<
Integer
>>
positionByPriority
)
{
Chromosome
neighbor
=
copyChromosome
(
chromosome
);
//
ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class);
List
<
Integer
>
os
=
neighbor
.
getOperationSequencing
();
if
(
os
.
size
()
>=
2
)
{
Map
<
Integer
,
Entry
>
positionIndex
=
buildPositionToEntryIndex
(
neighbor
,
entrys
);
// Map<Integer, Entry> positionIndex = buildPositionToEntryIndex(neighbor
);
int
maxAttempts
=
50
;
for
(
int
attempt
=
0
;
attempt
<
maxAttempts
;
attempt
++)
{
int
idx1
=
rnd
.
nextInt
(
os
.
size
());
int
idx2
=
rnd
.
nextInt
(
os
.
size
());
// 优先选择前面的优先级组(订单数多的),使用加权随机
int
priorityGroupIndex
;
if
(
positionByPriority
.
size
()
<=
3
)
{
priorityGroupIndex
=
rnd
.
nextInt
(
positionByPriority
.
size
());
}
else
{
// 70%概率选择前3个优先级组,30%概率选择其他
if
(
rnd
.
nextDouble
()
<
0.7
)
{
priorityGroupIndex
=
rnd
.
nextInt
(
Math
.
min
(
3
,
positionByPriority
.
size
()));
}
else
{
priorityGroupIndex
=
3
+
rnd
.
nextInt
(
positionByPriority
.
size
()
-
3
);
}
}
List
<
Integer
>
positionos
=
positionByPriority
.
get
(
priorityGroupIndex
);
if
(
positionos
.
size
()
<
2
)
continue
;
int
idx1InList
=
rnd
.
nextInt
(
positionos
.
size
());
int
idx2InList
=
rnd
.
nextInt
(
positionos
.
size
());
if
(
idx1InList
==
idx2InList
)
continue
;
int
idx1
=
positionos
.
get
(
idx1InList
);
int
idx2
=
positionos
.
get
(
idx2InList
);
if
(
idx1
==
idx2
)
continue
;
...
...
@@ -601,7 +1696,7 @@ public class VariableNeighborhoodSearch {
Entry
op2
=
positionIndex
.
get
(
idx2
);
if
(
op1
!=
null
&&
op2
!=
null
)
{
if
(
Math
.
abs
(
op1
.
getPriority
()
-
op2
.
getPriority
())
<
0.001
)
{
if
(
op1
.
getGroupId
()!=
op2
.
getGroupId
()
)
{
int
value
=
os
.
remove
(
idx1
);
os
.
add
(
idx2
,
value
);
neighbor
.
setOperationSequencing
(
os
);
...
...
@@ -617,7 +1712,7 @@ public class VariableNeighborhoodSearch {
* 生成机器选择邻域解 - 不受优先级限制
*/
private
Chromosome
generateMachineChangeNeighbor
(
Chromosome
chromosome
)
{
Chromosome
neighbor
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
Chromosome
neighbor
=
copyChromosome
(
chromosome
);
//
ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class);
List
<
Integer
>
ms
=
neighbor
.
getMachineSelection
();
if
(!
ms
.
isEmpty
())
{
int
idx
=
rnd
.
nextInt
(
ms
.
size
());
...
...
@@ -643,12 +1738,132 @@ public class VariableNeighborhoodSearch {
return
neighbor
;
}
Chromosome
generateSameMachineSwapNeighbor
(
Chromosome
chromosome
){
List
<
Integer
>
os
=
chromosome
.
getOperationSequencing
();
Map
<
String
,
Integer
>
machinePositionIndex
=
buildEntryMachinePositionIndex
(
chromosome
);
Map
<
Integer
,
Object
>
obj
=
buildPositionToEntryIndex
(
chromosome
);
Map
<
Integer
,
Entry
>
positionIndex
=(
Map
<
Integer
,
Entry
>)
obj
.
get
(
1
);
List
<
List
<
Integer
>>
positionByPriority
=
(
List
<
List
<
Integer
>>)
obj
.
get
(
2
);
return
generateSameMachineSwapNeighbor
(
chromosome
,
rnd
.
nextInt
(
os
.
size
()),
positionIndex
,
machinePositionIndex
);
}
private
Chromosome
generateSameMachineSwapNeighbor
(
Chromosome
chromosome
,
int
idx1
,
Map
<
Integer
,
Entry
>
positionIndex
,
Map
<
String
,
Integer
>
machinePositionIndex
)
{
Chromosome
neighbor
=
copyChromosome
(
chromosome
);
// ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class);
List
<
Integer
>
os
=
neighbor
.
getOperationSequencing
();
List
<
Integer
>
ms
=
neighbor
.
getMachineSelection
();
if
(
os
.
size
()
>=
2
&&
ms
.
size
()
>=
2
)
{
List
<
Integer
>
positions
=
new
ArrayList
<>();
Entry
op1
=
positionIndex
.
get
(
idx1
);
int
maPos1
=
machinePositionIndex
.
get
(
op1
.
getGroupId
()
+
"_"
+
op1
.
getSequence
());
int
machineSeq1
=
ms
.
get
(
maPos1
);
MachineOption
machineOption1
=
op1
.
getMachineOptions
().
get
(
machineSeq1
-
1
);
Long
machineId1
=
machineOption1
.
getMachineId
();
for
(
int
i
=
0
;
i
<
os
.
size
();
i
++)
{
Entry
op
=
positionIndex
.
get
(
i
);
if
(
op
==
null
)
continue
;
int
maPos
=
machinePositionIndex
.
get
(
op
.
getGroupId
()
+
"_"
+
op
.
getSequence
());
if
(
maPos
<
0
)
continue
;
int
machineSeq
=
ms
.
get
(
maPos
);
if
(
machineSeq
<
1
||
machineSeq
>
op
.
getMachineOptions
().
size
())
continue
;
MachineOption
machineOption
=
op
.
getMachineOptions
().
get
(
machineSeq
-
1
);
Long
machineId
=
machineOption
.
getMachineId
();
if
(
machineId
==
null
)
continue
;
if
(
machineId
.
equals
(
machineId1
)&&
Math
.
abs
(
op1
.
getPriority
()
-
op
.
getPriority
())==
0
&&
op1
.
getGroupId
()!=
op
.
getGroupId
())
{
positions
.
add
(
maPos
);
}
}
if
(
positions
.
isEmpty
()||
positions
.
size
()
<=
1
)
return
neighbor
;
int
idx2
=
positions
.
get
(
rnd
.
nextInt
(
positions
.
size
()));
Collections
.
swap
(
os
,
idx1
,
idx2
);
neighbor
.
setOperationSequencing
(
os
);
}
return
neighbor
;
}
// private Chromosome generateSameMachineSwapNeighbor(Chromosome chromosome,int idx1,Map<Integer, Entry> positionIndex,Map<String, Integer> machinePositionIndex) {
//
// Chromosome neighbor = ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class);
// List<Integer> os = neighbor.getOperationSequencing();
// List<Integer> ms = neighbor.getMachineSelection();
//
// if (os.size() >= 2 && ms.size() >= 2) {
//
// Map<Long, List<Integer>> machineToPositionsMap = new HashMap<>();
//
// for (int i = 0; i < os.size(); i++) {
// Entry op = positionIndex.get(i);
// if (op == null) continue;
//
// int maPos = machinePositionIndex.get(op.getGroupId() + "_" + op.getSequence());
// if (maPos < 0) continue;
//
// int machineSeq = ms.get(maPos);
// if (machineSeq < 1 || machineSeq > op.getMachineOptions().size()) continue;
//
// MachineOption machineOption = op.getMachineOptions().get(machineSeq - 1);
// Long machineId = machineOption.getMachineId();
// if (machineId == null) continue;
//
// machineToPositionsMap.computeIfAbsent(machineId, k -> new ArrayList<>()).add(i); }
//
// List<int[]> validPairs = new ArrayList<>();
//
// for (List<Integer> positions : machineToPositionsMap.values()) {
// if (positions.size() < 2) continue;
//
// for (int i = 0; i < positions.size(); i++) {
// for (int j = i + 1; j < positions.size(); j++) {
// int idx1 = positions.get(i);
// int idx2 = positions.get(j);
//
// Entry op1 = positionIndex.get(idx1);
// Entry op2 = positionIndex.get(idx2);
//
// if (op1 == null || op2 == null) continue;
// if (Math.abs(op1.getPriority() - op2.getPriority()) > 0.001) continue;
// if (op1.getGroupId()==(op2.getGroupId())) continue;
//
// validPairs.add(new int[]{idx1, idx2});
// }
// }
// }
//
// if (!validPairs.isEmpty()) {
// int[] pair = validPairs.get(rnd.nextInt(validPairs.size()));
// Collections.swap(os, pair[0], pair[1]);
// neighbor.setOperationSequencing(os);
// }
// }
// return neighbor;
// }
/**
* 局部搜索
*/
private
Chromosome
localSearch
(
Chromosome
chromosome
,
GeneticDecoder
decoder
,
ScheduleParams
param
)
{
private
Chromosome
localSearch
(
Chromosome
chromosome
,
GeneticDecoder
decoder
,
List
<
Machine
>
machines
)
{
Chromosome
current
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
Chromosome
best
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
decode
(
decoder
,
best
,
machines
);
//writeKpi(best);
// 预定义邻域结构,避免每次循环重复创建
List
<
NeighborhoodStructure
>
neighborhoods
=
defineNeighborhoods
();
boolean
improved
=
true
;
while
(
improved
)
{
...
...
@@ -656,15 +1871,25 @@ public class VariableNeighborhoodSearch {
// 生成所有可能的邻域解
List
<
Chromosome
>
neighbors
=
new
ArrayList
<>();
for
(
NeighborhoodStructure
neighborhood
:
defineNeighborhoods
())
{
neighbors
.
add
(
generateNeighbor
(
current
));
for
(
NeighborhoodStructure
neighborhood
:
neighborhoods
)
{
Chromosome
neighbor
=
generateNeighbor
(
current
,
neighborhood
);
if
(
neighbor
!=
null
)
{
neighbors
.
add
(
neighbor
);
}
}
if
(
neighbors
.
isEmpty
())
{
break
;
}
Batchdecode
(
decoder
,
neighbors
,
machines
);
// 评估所有邻域解
for
(
Chromosome
neighbor
:
neighbors
)
{
decode
(
decoder
,
neighbor
,
null
);
if
(
isBetter
(
neighbor
,
best
))
{
if
(
neighbor
!=
null
&&
isBetter
(
neighbor
,
best
))
{
best
=
neighbor
;
writeKpi
(
best
);
current
=
neighbor
;
improved
=
true
;
}
...
...
@@ -681,100 +1906,71 @@ public class VariableNeighborhoodSearch {
private
void
decode
(
GeneticDecoder
decoder
,
Chromosome
chromosome
,
List
<
Machine
>
machines
)
{
chromosome
.
setResult
(
new
CopyOnWriteArrayList
<>());
// 假设Machine类有拷贝方法,或使用MapStruct等工具进行映射
chromosome
.
setMachines
(
ProductionDeepCopyUtil
.
deepCopyList
(
machines
,
Machine
.
class
));
// 简单拷贝,实际可能需要深拷贝
decoder
.
decodeChromosomeWithCache
(
chromosome
);
}
/**
* 比较两个染色体的优劣
*/
private
boolean
isBetter
(
Chromosome
c1
,
Chromosome
c2
)
{
return
c1
.
getFitness
()
>
c2
.
getFitness
();
// 缓存 Machine 列表(第一次调用时缓存)
if
(
cachedMachines
==
null
)
{
cachedMachines
=
ProductionDeepCopyUtil
.
deepCopyList
(
machines
,
Machine
.
class
);
}
/**
* 邻域1:交换两个工序的顺序
*/
private
void
swapNeighborhood
(
Chromosome
chromosome
)
{
List
<
Integer
>
os
=
chromosome
.
getOperationSequencing
(
);
if
(
os
.
size
()
<
2
)
return
;
// 使用缓存的列表,避免重复深拷贝
chromosome
.
setMachines
(
ProductionDeepCopyUtil
.
deepCopyList
(
cachedMachines
,
Machine
.
class
));
chromosome
.
setOrders
(
ProductionDeepCopyUtil
.
deepCopyList
(
new
CopyOnWriteArrayList
<>(
cachedOrders
),
Order
.
class
));
chromosome
.
setOperatRel
(
ProductionDeepCopyUtil
.
deepCopyList
(
new
CopyOnWriteArrayList
<>(
cachedEntryRel
),
GroupResult
.
class
));
chromosome
.
setMaterials
(
ProductionDeepCopyUtil
.
deepCopyList
(
cachedMaterials
,
Material
.
class
)
);
chromosome
.
setAllOperations
(
ProductionDeepCopyUtil
.
deepCopyList
(
new
CopyOnWriteArrayList
<>(
cachedAllOperations
),
Entry
.
class
))
;
int
idx1
=
rnd
.
nextInt
(
os
.
size
());
int
idx2
=
rnd
.
nextInt
(
os
.
size
());
while
(
idx2
==
idx1
)
{
idx2
=
rnd
.
nextInt
(
os
.
size
());
// 加载锁定工单到ResultOld
List
<
GAScheduleResult
>
lockedOrders
=
GlobalCacheUtil
.
get
(
"locked_orders_"
+
chromosome
.
getScenarioID
());
if
(
lockedOrders
!=
null
&&
!
lockedOrders
.
isEmpty
())
{
chromosome
.
setResultOld
(
ProductionDeepCopyUtil
.
deepCopyList
(
lockedOrders
,
GAScheduleResult
.
class
));
}
else
{
chromosome
.
setResultOld
(
new
CopyOnWriteArrayList
<>());
}
decoder
.
decodeChromosomeWithCache
(
chromosome
,
true
);
}
Collections
.
swap
(
os
,
idx1
,
idx2
);
chromosome
.
setOperationSequencing
(
os
);
private
void
Batchdecode
(
GeneticDecoder
decoder
,
List
<
Chromosome
>
chromosomes
,
List
<
Machine
>
machines
)
{
// 缓存 Machine 列表(第一次调用时缓存)
if
(
cachedMachines
==
null
)
{
cachedMachines
=
ProductionDeepCopyUtil
.
deepCopyList
(
machines
,
Machine
.
class
);
}
log
(
String
.
format
(
"变邻域搜索 -复制对象S, 染色体数="
+
chromosomes
.
size
()));
/**
* 邻域2:反转一个工序子序列
*/
private
void
reverseNeighborhood
(
Chromosome
chromosome
)
{
List
<
Integer
>
os
=
chromosome
.
getOperationSequencing
();
if
(
os
.
size
()
<
2
)
return
;
// 并行设置染色体字段
chromosomes
.
parallelStream
().
forEach
(
chromosome
->
{
if
(
chromosome
==
null
)
return
;
int
start
=
rnd
.
nextInt
(
os
.
size
());
int
end
=
rnd
.
nextInt
(
os
.
size
());
while
(
end
<=
start
)
{
end
=
rnd
.
nextInt
(
os
.
size
());
}
chromosome
.
setResult
(
new
CopyOnWriteArrayList
<>());
Collections
.
reverse
(
os
.
subList
(
start
,
end
+
1
));
chromosome
.
setOperationSequencing
(
os
);
// 使用缓存的列表,避免重复深拷贝
chromosome
.
setMachines
(
ProductionDeepCopyUtil
.
deepCopyList
(
cachedMachines
,
Machine
.
class
));
chromosome
.
setOrders
(
ProductionDeepCopyUtil
.
deepCopyList
(
new
CopyOnWriteArrayList
<>(
cachedOrders
),
Order
.
class
));
chromosome
.
setOperatRel
(
ProductionDeepCopyUtil
.
deepCopyList
(
new
CopyOnWriteArrayList
<>(
cachedEntryRel
),
GroupResult
.
class
));
chromosome
.
setMaterials
(
ProductionDeepCopyUtil
.
deepCopyList
(
cachedMaterials
,
Material
.
class
));
chromosome
.
setAllOperations
(
ProductionDeepCopyUtil
.
deepCopyList
(
new
CopyOnWriteArrayList
<>(
cachedAllOperations
),
Entry
.
class
));
// 加载锁定工单到ResultOld
List
<
GAScheduleResult
>
lockedOrders
=
GlobalCacheUtil
.
get
(
"locked_orders_"
+
chromosome
.
getScenarioID
());
if
(
lockedOrders
!=
null
&&
!
lockedOrders
.
isEmpty
())
{
chromosome
.
setResultOld
(
ProductionDeepCopyUtil
.
deepCopyList
(
lockedOrders
,
GAScheduleResult
.
class
));
}
else
{
chromosome
.
setResultOld
(
new
CopyOnWriteArrayList
<>());
}
});
/**
* 邻域3:插入一个工序到另一个位置
*/
private
void
insertNeighborhood
(
Chromosome
chromosome
)
{
List
<
Integer
>
os
=
chromosome
.
getOperationSequencing
();
if
(
os
.
size
()
<
2
)
return
;
log
(
String
.
format
(
"变邻域搜索 -复制对象E"
));
int
idx1
=
rnd
.
nextInt
(
os
.
size
());
int
idx2
=
rnd
.
nextInt
(
os
.
size
());
while
(
idx2
==
idx1
)
{
idx2
=
rnd
.
nextInt
(
os
.
size
());
// 并行解码所有候选方案
decoder
.
Chromosomedecode
(
chromosomes
);
}
int
value
=
os
.
remove
(
idx1
);
os
.
add
(
idx2
,
value
);
chromosome
.
setOperationSequencing
(
os
);
}
/**
*
邻域4:机器选择变异
*
比较两个染色体的优劣
*/
private
void
machineChangeNeighborhood
(
Chromosome
chromosome
)
{
List
<
Integer
>
ms
=
chromosome
.
getMachineSelection
();
if
(
ms
.
isEmpty
())
return
;
int
idx
=
rnd
.
nextInt
(
ms
.
size
());
GlobalOperationInfo
globalOp
=
chromosome
.
getGlobalOpList
().
get
(
idx
);
Entry
op
=
globalOp
.
getOp
();
if
(
op
.
getMachineOptions
().
size
()
>
1
)
{
int
currentMachineSeq
=
ms
.
get
(
idx
);
List
<
Integer
>
availableMachines
=
new
ArrayList
<>();
for
(
int
i
=
1
;
i
<=
op
.
getMachineOptions
().
size
();
i
++)
{
if
(
i
!=
currentMachineSeq
)
{
availableMachines
.
add
(
i
);
}
private
boolean
isBetter
(
Chromosome
c1
,
Chromosome
c2
)
{
return
fitnessCalculator
.
isBetter
(
c1
,
c2
);
}
if
(!
availableMachines
.
isEmpty
())
{
int
newMachineSeq
=
availableMachines
.
get
(
rnd
.
nextInt
(
availableMachines
.
size
()));
ms
.
set
(
idx
,
newMachineSeq
);
chromosome
.
setMachineSelection
(
ms
);
}
}
}
/**
* 构建位置索引:groupId_sequence -> position
*/
...
...
@@ -791,6 +1987,8 @@ public class VariableNeighborhoodSearch {
String
key
=
groupId
+
"_"
+
count
;
index
.
put
(
key
,
i
);
}
return
index
;
}
...
...
@@ -816,8 +2014,15 @@ public class VariableNeighborhoodSearch {
/**
* 构建位置->Entry索引
*/
private
Map
<
Integer
,
Entry
>
buildPositionToEntryIndex
(
Chromosome
chromosome
,
Map
<
String
,
Entry
>
entrys
)
{
private
Map
<
Integer
,
Object
>
buildPositionToEntryIndex
(
Chromosome
chromosome
)
{
Map
<
Integer
,
Object
>
obj
=
new
HashMap
<>();
Map
<
Integer
,
Entry
>
index
=
new
HashMap
<>();
//将位置按照优先级分组
Map
<
Double
,
List
<
Integer
>>
indexByPriorityMap
=
new
HashMap
<>();
Map
<
Double
,
Set
<
Integer
>>
groupidByPriority
=
new
HashMap
<>();
List
<
Integer
>
os
=
chromosome
.
getOperationSequencing
();
Map
<
Integer
,
Integer
>
orderProcessCounter
=
new
HashMap
<>();
...
...
@@ -831,9 +2036,30 @@ public class VariableNeighborhoodSearch {
if
(
op
!=
null
)
{
index
.
put
(
i
,
op
);
double
priority
=
op
.
getPriority
();
indexByPriorityMap
.
computeIfAbsent
(
priority
,
k
->
new
ArrayList
<>()).
add
(
i
);
groupidByPriority
.
computeIfAbsent
(
priority
,
k
->
new
HashSet
()).
add
(
op
.
getGroupId
());
}
}
return
index
;
groupidByPriority
.
entrySet
().
removeIf
(
entry
->
entry
.
getValue
().
size
()
==
1
);
indexByPriorityMap
.
keySet
().
removeIf
(
key
->
!
groupidByPriority
.
containsKey
(
key
));
List
<
Map
.
Entry
<
Double
,
List
<
Integer
>>>
sortedEntries
=
new
ArrayList
<>(
indexByPriorityMap
.
entrySet
());
sortedEntries
.
sort
((
e1
,
e2
)
->
{
int
size1
=
groupidByPriority
.
get
(
e1
.
getKey
()).
size
();
int
size2
=
groupidByPriority
.
get
(
e2
.
getKey
()).
size
();
return
Integer
.
compare
(
size2
,
size1
);
// 降序:订单数多的排前面
});
List
<
List
<
Integer
>>
indexByPriority
=
new
ArrayList
<>();
for
(
Map
.
Entry
<
Double
,
List
<
Integer
>>
entry
:
sortedEntries
)
{
indexByPriority
.
add
(
entry
.
getValue
());
}
obj
.
put
(
1
,
index
);
obj
.
put
(
2
,
indexByPriority
);
return
obj
;
}
/**
...
...
@@ -860,7 +2086,7 @@ public class VariableNeighborhoodSearch {
* 邻域结构接口
*/
private
interface
NeighborhoodOperator
{
void
apply
(
Chromosome
chromosome
);
Chromosome
apply
(
Chromosome
chromosome
);
}
/**
...
...
@@ -875,8 +2101,8 @@ public class VariableNeighborhoodSearch {
this
.
operator
=
operator
;
}
public
void
apply
(
Chromosome
chromosome
)
{
operator
.
apply
(
chromosome
);
public
Chromosome
apply
(
Chromosome
chromosome
)
{
return
operator
.
apply
(
chromosome
);
}
}
}
\ No newline at end of file
src/main/java/com/aps/service/plan/SceneService.java
View file @
8a7de711
...
...
@@ -132,7 +132,7 @@ public class SceneService {
try
{
ObjectMapper
objectMapper
=
createObjectMapper
();
SceneChromsome
sceneChromsome
=(
SceneChromsome
)
redisUtils
.
get
(
"SceneId."
+
sceneId
);
SceneChromsome
sceneChromsome
=
null
;
//
(SceneChromsome)redisUtils.get("SceneId."+sceneId);
if
(
sceneChromsome
==
null
)
{
sceneChromsome
=
new
SceneChromsome
();
...
...
@@ -163,7 +163,7 @@ public class SceneService {
sceneChromsome
.
getSceneDetails
().
add
(
sceneDetail
);
redisUtils
.
set
(
"SceneId."
+
sceneId
,
sceneChromsome
);
//
redisUtils.set("SceneId."+sceneId,sceneChromsome);
File
file
=
getChromosomeFile
(
sceneId
,
sceneChromsome
.
getVersion
().
toString
());
...
...
src/test/java/com/aps/demo/PlanResultServiceTest.java
View file @
8a7de711
...
...
@@ -39,7 +39,8 @@ public class PlanResultServiceTest {
// TestSortService sortService=new TestSortService();
// sortService.test1();
// nsgaiiUtils.Test();
planResultService
.
execute2
(
"0428340BB4F540938F1FB5599F03E8A4"
);
//2000
planResultService
.
execute2
(
"08B1D87FE1B84ECDBAC2E546DDB6FB81"
);
//2000
// planResultService.execute2("0428340BB4F540938F1FB5599F03E8A4");//2000
// planResultService.execute2("C8B533BD8944405B9A2F8823C575C204");//500
// planResultService.execute2("EFDD34E4B5BC434BAEAE6A84DFCD4E7B");//20
// planResultService.execute2("00E0C5D3E4AD4F36B56C39395906618D");
...
...
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