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
f2a1529b
Commit
f2a1529b
authored
Apr 12, 2026
by
Tong Li
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/tl'
parents
bb00017a
f1998b61
Show whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
3554 additions
and
2122 deletions
+3554
-2122
Chromosome.java
src/main/java/com/aps/entity/Algorithm/Chromosome.java
+44
-18
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
Order.java
src/main/java/com/aps/entity/basic/Order.java
+5
-0
FitnessCalculator.java
...ain/java/com/aps/service/Algorithm/FitnessCalculator.java
+20
-1
GeneticAlgorithm.java
...main/java/com/aps/service/Algorithm/GeneticAlgorithm.java
+1
-1
GeneticDecoder.java
src/main/java/com/aps/service/Algorithm/GeneticDecoder.java
+151
-262
GeneticOperations.java
...ain/java/com/aps/service/Algorithm/GeneticOperations.java
+7
-1
HillClimbing.java
src/main/java/com/aps/service/Algorithm/HillClimbing.java
+55
-124
HybridAlgorithm.java
src/main/java/com/aps/service/Algorithm/HybridAlgorithm.java
+135
-182
Initialization.java
src/main/java/com/aps/service/Algorithm/Initialization.java
+1
-1
MaterialRequirementService.java
...com/aps/service/Algorithm/MaterialRequirementService.java
+216
-218
MaterialRequirementServicebf.java
...m/aps/service/Algorithm/MaterialRequirementServicebf.java
+1
-1
ParallelLocalSearch.java
...n/java/com/aps/service/Algorithm/ParallelLocalSearch.java
+0
-91
ScheduleOperationService.java
...a/com/aps/service/Algorithm/ScheduleOperationService.java
+1
-1
SimulatedAnnealing.java
...in/java/com/aps/service/Algorithm/SimulatedAnnealing.java
+304
-644
TabuSearch.java
src/main/java/com/aps/service/Algorithm/TabuSearch.java
+247
-173
TabuSearchWithSA.java
...main/java/com/aps/service/Algorithm/TabuSearchWithSA.java
+0
-271
VariableNeighborhoodSearch.java
...com/aps/service/Algorithm/VariableNeighborhoodSearch.java
+2340
-120
PlanResultService.java
src/main/java/com/aps/service/plan/PlanResultService.java
+2
-2
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/Chromosome.java
View file @
f2a1529b
...
@@ -32,6 +32,11 @@ public class Chromosome {
...
@@ -32,6 +32,11 @@ public class Chromosome {
/// </summary>
/// </summary>
private
List
<
Integer
>
machineSelection
;
private
List
<
Integer
>
machineSelection
;
// 缓存标记
private
transient
boolean
machineStrDirty
=
true
;
private
transient
boolean
operationStrDirty
=
true
;
private
transient
boolean
geneStrDirty
=
true
;
/// <summary>
/// <summary>
/// 工序排序部分(工件/订单ID)
/// 工序排序部分(工件/订单ID)
/// </summary>
/// </summary>
...
@@ -43,7 +48,10 @@ public class Chromosome {
...
@@ -43,7 +48,10 @@ public class Chromosome {
private
String
geneStr
;
private
String
geneStr
;
public
String
getGeneStr
()
{
public
String
getGeneStr
()
{
geneStr
=
getMachineStr
()+
"_"
+
getOperationStr
();
if
(
geneStrDirty
||
machineStrDirty
||
operationStrDirty
)
{
geneStr
=
getMachineStr
()
+
"_"
+
getOperationStr
();
geneStrDirty
=
false
;
}
return
geneStr
;
return
geneStr
;
}
}
...
@@ -51,26 +59,44 @@ public class Chromosome {
...
@@ -51,26 +59,44 @@ public class Chromosome {
public
String
getMachineStr
()
{
public
String
getMachineStr
()
{
if
(
machineStrDirty
)
{
machineStr
=
Optional
.
ofNullable
(
machineSelection
)
machineStr
=
Optional
.
ofNullable
(
machineSelection
)
.
orElse
(
Collections
.
emptyList
())
.
orElse
(
Collections
.
emptyList
())
.
stream
()
.
stream
()
.
map
(
String:
:
valueOf
)
// Integer转String
.
map
(
String:
:
valueOf
)
.
collect
(
Collectors
.
joining
(
","
));
.
collect
(
Collectors
.
joining
(
","
));
machineStrDirty
=
false
;
geneStrDirty
=
true
;
}
return
machineStr
;
return
machineStr
;
}
}
public
String
getOperationStr
()
{
public
String
getOperationStr
()
{
if
(
operationStrDirty
)
{
operationStr
=
Optional
.
ofNullable
(
operationSequencing
)
operationStr
=
Optional
.
ofNullable
(
operationSequencing
)
.
orElse
(
Collections
.
emptyList
())
.
orElse
(
Collections
.
emptyList
())
.
stream
()
.
stream
()
.
map
(
String:
:
valueOf
)
// Integer转String
.
map
(
String:
:
valueOf
)
.
collect
(
Collectors
.
joining
(
","
));
.
collect
(
Collectors
.
joining
(
","
));
operationStrDirty
=
false
;
geneStrDirty
=
true
;
}
return
operationStr
;
return
operationStr
;
}
}
// 重写 setter 方法,在设置时标记为脏
public
void
setMachineSelection
(
List
<
Integer
>
machineSelection
)
{
this
.
machineSelection
=
machineSelection
;
this
.
machineStrDirty
=
true
;
this
.
geneStrDirty
=
true
;
}
public
void
setOperationSequencing
(
List
<
Integer
>
operationSequencing
)
{
this
.
operationSequencing
=
operationSequencing
;
this
.
operationStrDirty
=
true
;
this
.
geneStrDirty
=
true
;
}
...
...
src/main/java/com/aps/entity/Algorithm/ScheduleParams.java
View file @
f2a1529b
...
@@ -15,7 +15,7 @@ public class ScheduleParams {
...
@@ -15,7 +15,7 @@ public class ScheduleParams {
// 基础参数(自适应调整的基准值)
// 基础参数(自适应调整的基准值)
private
static
final
int
MIN_POPULATION_SIZE
=
10
;
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
MIN_MAX_ITERATIONS
=
50
;
private
static
final
int
MAX_MAX_ITERATIONS
=
100
;
private
static
final
int
MAX_MAX_ITERATIONS
=
100
;
private
static
final
float
MIN_CROSSOVER_PROB
=
0.6f
;
private
static
final
float
MIN_CROSSOVER_PROB
=
0.6f
;
...
@@ -172,10 +172,14 @@ public class ScheduleParams {
...
@@ -172,10 +172,14 @@ public class ScheduleParams {
// 1. 种群大小:50 ~ 500,随工序数线性增加
// 1. 种群大小:50 ~ 500,随工序数线性增加
populationSize
=
(
int
)
Math
.
max
(
MIN_POPULATION_SIZE
,
populationSize
=
(
int
)
Math
.
max
(
MIN_POPULATION_SIZE
,
Math
.
min
(
MAX_POPULATION_SIZE
,
MIN_POPULATION_SIZE
+
totalOps
*
populationSizeCoeff
));
Math
.
min
(
MAX_POPULATION_SIZE
,
MIN_POPULATION_SIZE
+
totalOps
*
populationSizeCoeff
));
int
maxthead
=
Runtime
.
getRuntime
().
availableProcessors
()
-
1
;
populationSize
=
populationSize
/
maxthead
*
maxthead
;
// 确保偶数(方便交叉)
// 确保偶数(方便交叉)
if
(
populationSize
%
2
!=
0
)
{
//
if (populationSize % 2 != 0) {
populationSize
+=
1
;
//
populationSize += 1;
}
//
}
// 2. 最大迭代次数:50 ~ 200,随工序数线性减少
// 2. 最大迭代次数:50 ~ 200,随工序数线性减少
maxIterations
=
(
int
)
Math
.
max
(
MIN_MAX_ITERATIONS
,
maxIterations
=
(
int
)
Math
.
max
(
MIN_MAX_ITERATIONS
,
...
...
src/main/java/com/aps/entity/basic/GlobalParam.java
View file @
f2a1529b
...
@@ -73,11 +73,11 @@ public class GlobalParam {
...
@@ -73,11 +73,11 @@ public class GlobalParam {
public
GlobalParam
()
{
public
GlobalParam
()
{
// 初始化默认目标值配置
// 初始化默认目标值配置
//完工时间、总流程时间、总换型时间、机器负载标准差、延迟时间
//完工时间、总流程时间、总换型时间、机器负载标准差、延迟时间
objectiveConfigs
.
add
(
new
ObjectiveConfig
(
OBJECTIVE_MAKESPAN
,
true
,
1
,
0.
6
));
objectiveConfigs
.
add
(
new
ObjectiveConfig
(
OBJECTIVE_MAKESPAN
,
true
,
1
,
0.
3
));
objectiveConfigs
.
add
(
new
ObjectiveConfig
(
OBJECTIVE_FLOW_TIME
,
fals
e
,
2
,
0.1
));
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_SETUP_TIME
,
true
,
2
,
0.1
));
objectiveConfigs
.
add
(
new
ObjectiveConfig
(
OBJECTIVE_MACHINE_LOAD
,
false
,
3
,
0.1
));
objectiveConfigs
.
add
(
new
ObjectiveConfig
(
OBJECTIVE_MACHINE_LOAD
,
true
,
1
,
0.1
));
objectiveConfigs
.
add
(
new
ObjectiveConfig
(
OBJECTIVE_TARDINESS
,
true
,
1
,
0.
3
));
objectiveConfigs
.
add
(
new
ObjectiveConfig
(
OBJECTIVE_TARDINESS
,
true
,
1
,
0.
6
));
objectiveConfigs
.
sort
(
Comparator
.
comparing
((
ObjectiveConfig
op
)
->
op
.
getLevel
()));
objectiveConfigs
.
sort
(
Comparator
.
comparing
((
ObjectiveConfig
op
)
->
op
.
getLevel
()));
}
}
...
...
src/main/java/com/aps/entity/basic/KpiTargetConfig.java
0 → 100644
View file @
f2a1529b
package
com
.
aps
.
entity
.
basic
;
/**
* 作者:佟礼
* 时间:2026-04-09
*/
public
class
KpiTargetConfig
{
}
src/main/java/com/aps/entity/basic/Order.java
View file @
f2a1529b
...
@@ -157,6 +157,11 @@ public class Order {
...
@@ -157,6 +157,11 @@ public class Order {
*/
*/
private
boolean
newCreate
=
false
;
private
boolean
newCreate
=
false
;
/**
* 是否新创建半成品,默认值:false
*/
private
boolean
newSfCreate
=
false
;
/**
/**
* 是否创建BOM,默认值:false
* 是否创建BOM,默认值:false
*/
*/
...
...
src/main/java/com/aps/service/Algorithm/FitnessCalculator.java
View file @
f2a1529b
...
@@ -21,8 +21,10 @@ public class FitnessCalculator {
...
@@ -21,8 +21,10 @@ public class FitnessCalculator {
ArrayList
<
Double
>
list
=
new
ArrayList
<>();
ArrayList
<
Double
>
list
=
new
ArrayList
<>();
double
fitness
=
0
;
double
fitness
=
0
;
double
total
=
0
;
int
i
=
0
;
int
i
=
0
;
int
level
=-
1
;
int
level
=-
1
;
double
[]
weightedObjectives
=
new
double
[
chromosome
.
getObjectives
().
length
];
for
(
ObjectiveConfig
config
:
param
.
getObjectiveConfigs
())
{
for
(
ObjectiveConfig
config
:
param
.
getObjectiveConfigs
())
{
if
(
config
.
isEnabled
())
{
if
(
config
.
isEnabled
())
{
...
@@ -65,7 +67,9 @@ public class FitnessCalculator {
...
@@ -65,7 +67,9 @@ public class FitnessCalculator {
if
(!
param
.
isPureNSGAIIMode
())
{
if
(!
param
.
isPureNSGAIIMode
())
{
val
=
val
*
config
.
getWeight
();
val
=
val
*
config
.
getWeight
();
}
}
weightedObjectives
[
i
]=
val
;
fitness
+=
val
;
fitness
+=
val
;
total
+=
val
;
i
++;
i
++;
}
}
}
}
...
@@ -87,6 +91,8 @@ public class FitnessCalculator {
...
@@ -87,6 +91,8 @@ public class FitnessCalculator {
// fitness ≈ 0.01
// fitness ≈ 0.01
// 适应度值(越大越好)
// 适应度值(越大越好)
chromosome
.
setFitness
(
total
);
chromosome
.
setWeightedObjectives
(
weightedObjectives
);
return
list
.
stream
().
mapToDouble
(
Double:
:
doubleValue
).
toArray
();
return
list
.
stream
().
mapToDouble
(
Double:
:
doubleValue
).
toArray
();
}
}
...
@@ -147,7 +153,7 @@ public class FitnessCalculator {
...
@@ -147,7 +153,7 @@ public class FitnessCalculator {
// 2. 计算每个个体与平均值的平方差之和
// 2. 计算每个个体与平均值的平方差之和
float
sumSqDiff
=
0.0f
;
float
sumSqDiff
=
0.0f
;
for
(
Chromosome
chromosome
:
population
)
{
for
(
Chromosome
chromosome
:
population
)
{
double
diff
=
chromosome
.
get
WeightedObjective
()
-
avgFitness
;
double
diff
=
chromosome
.
get
Fitness
()
-
avgFitness
;
sumSqDiff
+=
diff
*
diff
;
sumSqDiff
+=
diff
*
diff
;
}
}
...
@@ -155,6 +161,19 @@ public class FitnessCalculator {
...
@@ -155,6 +161,19 @@ public class FitnessCalculator {
return
(
double
)
Math
.
sqrt
(
sumSqDiff
/
popSize
);
return
(
double
)
Math
.
sqrt
(
sumSqDiff
/
popSize
);
}
}
/**
* 比较两个染色体的优劣(基于fitnessLevel多层次比较)
*/
public
boolean
isBetter
(
Chromosome
c1
,
Chromosome
c2
)
{
for
(
int
i
=
0
;
i
<
c1
.
getFitnessLevel
().
length
;
i
++)
{
double
[]
Fitness1
=
c1
.
getFitnessLevel
();
double
[]
Fitness2
=
c2
.
getFitnessLevel
();
if
(
Fitness1
[
i
]
>
Fitness2
[
i
])
{
return
true
;
}
}
return
false
;
}
...
...
src/main/java/com/aps/service/Algorithm/GeneticAlgorithm.java
View file @
f2a1529b
...
@@ -425,7 +425,7 @@ public class GeneticAlgorithm {
...
@@ -425,7 +425,7 @@ public class GeneticAlgorithm {
// chromosome.setResultOld(new CopyOnWriteArrayList<>());
// chromosome.setResultOld(new CopyOnWriteArrayList<>());
// }
// }
decoder
.
decodeChromosomeWithCache
(
chromosome
);
decoder
.
decodeChromosomeWithCache
(
chromosome
,
false
);
if
(
chromosome
.
getFitness
()
==
0
)
{
if
(
chromosome
.
getFitness
()
==
0
)
{
chromosome
.
setFitness
(
_fitnessCalculator
.
calculateFitness
(
chromosome
,
_objectiveWeights
));
chromosome
.
setFitness
(
_fitnessCalculator
.
calculateFitness
(
chromosome
,
_objectiveWeights
));
}
}
...
...
src/main/java/com/aps/service/Algorithm/GeneticDecoder.java
View file @
f2a1529b
...
@@ -88,17 +88,17 @@ public class GeneticDecoder {
...
@@ -88,17 +88,17 @@ public class GeneticDecoder {
{
{
FileHelper
.
writeLogFile
(
"解码---------------"
+
population
.
size
()
);
FileHelper
.
writeLogFile
(
"解码---------------"
+
population
.
size
()
);
boolean
ismore
=
fals
e
;
boolean
ismore
=
tru
e
;
if
(
ismore
)
{
if
(
ismore
)
{
CompletableFuture
.
allOf
(
population
.
stream
()
CompletableFuture
.
allOf
(
population
.
stream
()
.
map
(
chromosome
->
CompletableFuture
.
runAsync
(()
->
decodeChromosomeWithCache
(
chromosome
),
decodeExecutor
))
.
map
(
chromosome
->
CompletableFuture
.
runAsync
(()
->
decodeChromosomeWithCache
(
chromosome
,
false
),
decodeExecutor
))
.
toArray
(
CompletableFuture
[]::
new
))
.
toArray
(
CompletableFuture
[]::
new
))
.
join
();
.
join
();
}
else
{
}
else
{
if
(
population
!=
null
&&
population
.
size
()
>
0
)
{
if
(
population
!=
null
&&
population
.
size
()
>
0
)
{
population
.
forEach
(
chromosome
->
{
population
.
forEach
(
chromosome
->
{
decodeChromosomeWithCache
(
chromosome
);
decodeChromosomeWithCache
(
chromosome
,
false
);
});
});
}
}
}
}
...
@@ -176,7 +176,7 @@ public class GeneticDecoder {
...
@@ -176,7 +176,7 @@ public class GeneticDecoder {
// return chromosome;
// return chromosome;
// }
// }
public
Chromosome
decodeChromosomeWithCache
(
Chromosome
chromosome
)
{
public
Chromosome
decodeChromosomeWithCache
(
Chromosome
chromosome
,
boolean
isParallel
)
{
String
cacheKey
=
createCacheKey
(
chromosome
);
String
cacheKey
=
createCacheKey
(
chromosome
);
// FileHelper.writeLogFile("解码-----------开始-------"+chromosome.getID()+":"+cacheKey );
// FileHelper.writeLogFile("解码-----------开始-------"+chromosome.getID()+":"+cacheKey );
...
@@ -214,7 +214,7 @@ public class GeneticDecoder {
...
@@ -214,7 +214,7 @@ public class GeneticDecoder {
return
chromosome
;
return
chromosome
;
}
}
// 3. 缓存未命中:执行解码逻辑
// 3. 缓存未命中:执行解码逻辑
decode
(
chromosome
);
decode
(
chromosome
,
isParallel
);
// 4. 将解码结果存入缓存(无锁,ConcurrentHashMap 线程安全)
// 4. 将解码结果存入缓存(无锁,ConcurrentHashMap 线程安全)
decodingCache
.
putIfAbsent
(
cacheKey
,
chromosome
);
decodingCache
.
putIfAbsent
(
cacheKey
,
chromosome
);
...
@@ -266,7 +266,7 @@ public class GeneticDecoder {
...
@@ -266,7 +266,7 @@ public class GeneticDecoder {
Initialization
initialization
=
new
Initialization
();
Initialization
initialization
=
new
Initialization
();
initialization
.
generateInitialSFPopulation
(
chromosome
,
globalOpList
);
initialization
.
generateInitialSFPopulation
(
chromosome
,
globalOpList
);
chromosome
.
getGlobalOpList
().
addAll
(
globalOpList
);
chromosome
.
getGlobalOpList
().
addAll
(
globalOpList
);
return
1
;
return
1
;
}
}
private
void
CreateNewOpSequence
(
Chromosome
chromosome
)
private
void
CreateNewOpSequence
(
Chromosome
chromosome
)
...
@@ -279,10 +279,10 @@ return 1;
...
@@ -279,10 +279,10 @@ return 1;
.
distinct
()
.
distinct
()
.
collect
(
Collectors
.
toList
());
.
collect
(
Collectors
.
toList
());
if
(
finishedOrder
==
null
||
finishedOrder
.
size
()==
0
)
if
(
finishedOrder
==
null
||
finishedOrder
.
size
()==
0
)
{
{
return
;
return
;
}
}
List
<
Integer
>
oldSequence
=
chromosome
.
getOperationSequencing
();
List
<
Integer
>
oldSequence
=
chromosome
.
getOperationSequencing
();
List
<
Integer
>
finalSequence
=
new
ArrayList
<>();
List
<
Integer
>
finalSequence
=
new
ArrayList
<>();
...
@@ -367,12 +367,11 @@ if(finishedOrder==null||finishedOrder.size()==0)
...
@@ -367,12 +367,11 @@ if(finishedOrder==null||finishedOrder.size()==0)
orderProcessCounter
.
put
(
orderid
,
scheduledCount
);
orderProcessCounter
.
put
(
orderid
,
scheduledCount
);
}
}
public
void
decode
(
Chromosome
chromosome
)
{
public
void
decode
(
Chromosome
chromosome
,
boolean
isParallel
)
{
int
operationCount
=
chromosome
.
getAllOperations
().
size
();
int
cpuCores
=
Runtime
.
getRuntime
().
availableProcessors
();
//
//
// // 根据工序数量和CPU核心数决定是否使用内部并行
// // 根据工序数量和CPU核心数决定是否使用内部并行
if
(
operationCount
>
5000
&&
cpuCores
>
4
)
{
if
(
isParallel
)
{
// 使用设备并行处理
// 使用设备并行处理
// FileHelper.writeLogFile("使用并行处理 _s");
// FileHelper.writeLogFile("使用并行处理 _s");
parallelDecodeByMachine
(
chromosome
);
parallelDecodeByMachine
(
chromosome
);
...
@@ -392,7 +391,7 @@ if(finishedOrder==null||finishedOrder.size()==0)
...
@@ -392,7 +391,7 @@ if(finishedOrder==null||finishedOrder.size()==0)
public
void
serialDecode
(
Chromosome
chromosome
)
{
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
);
chromosome
.
setScenarioID
(
sceneId
);
if
(
_globalParam
.
isIsCheckSf
())
{
if
(
_globalParam
.
isIsCheckSf
())
{
int
isnew
=
generateGlobalOpList
(
chromosome
);
int
isnew
=
generateGlobalOpList
(
chromosome
);
...
@@ -473,12 +472,15 @@ if(finishedOrder==null||finishedOrder.size()==0)
...
@@ -473,12 +472,15 @@ if(finishedOrder==null||finishedOrder.size()==0)
Map
<
Integer
,
Integer
>
orderLastEndTime
=
new
HashMap
<>();
Map
<
Integer
,
Integer
>
orderLastEndTime
=
new
HashMap
<>();
Map
<
Integer
,
Entry
>
entryIndexById
=
new
HashMap
<>();
Map
<
Integer
,
Entry
>
entryIndexById
=
new
HashMap
<>();
Map
<
Integer
,
List
<
Entry
>>
entrysBygroupId
=
new
HashMap
<>();
Map
<
Integer
,
List
<
Entry
>>
entrysBygroupId
=
new
HashMap
<>();
Map
<
Integer
,
GAScheduleResult
>
scheduleIndexById
=
new
ConcurrentHashMap
<>();
for
(
Entry
op
:
allOperations
)
{
for
(
Entry
op
:
allOperations
)
{
int
groupId
=
op
.
getGroupId
();
int
groupId
=
op
.
getGroupId
();
orderProcessCounter
.
putIfAbsent
(
groupId
,
0
);
orderProcessCounter
.
putIfAbsent
(
groupId
,
0
);
orderLastEndTime
.
putIfAbsent
(
groupId
,
0
);
orderLastEndTime
.
putIfAbsent
(
groupId
,
0
);
entryIndexById
.
put
(
op
.
getId
(),
op
);
entryIndexById
.
put
(
op
.
getId
(),
op
);
entrysBygroupId
.
computeIfAbsent
(
groupId
,
k
->
new
ArrayList
<>()).
add
(
op
);
entrysBygroupId
.
computeIfAbsent
(
groupId
,
k
->
new
ArrayList
<>()).
add
(
op
);
//scheduleIndexById.put(op.getId(),null);
}
}
// Map<Long, String> machineState = chromosome.getMachines().stream()
// Map<Long, String> machineState = chromosome.getMachines().stream()
...
@@ -487,9 +489,7 @@ if(finishedOrder==null||finishedOrder.size()==0)
...
@@ -487,9 +489,7 @@ if(finishedOrder==null||finishedOrder.size()==0)
// List<Entry> allScheduledOps = new ArrayList<>();
// List<Entry> allScheduledOps = new ArrayList<>();
// 缓存机器任务
// 缓存机器任务
Map
<
Long
,
CopyOnWriteArrayList
<
GAScheduleResult
>>
machineTasksCache
=
new
HashMap
<>();
Map
<
Long
,
CopyOnWriteArrayList
<
GAScheduleResult
>>
machineTasksCache
=
new
HashMap
<>();
for
(
Entry
op
:
allOperations
)
{
}
for
(
int
groupId
:
chromosome
.
getOperationSequencing
())
{
for
(
int
groupId
:
chromosome
.
getOperationSequencing
())
{
int
scheduledCount
=
orderProcessCounter
.
get
(
groupId
);
int
scheduledCount
=
orderProcessCounter
.
get
(
groupId
);
List
<
Entry
>
orderOps
=
entrysBygroupId
.
get
(
groupId
).
stream
()
List
<
Entry
>
orderOps
=
entrysBygroupId
.
get
(
groupId
).
stream
()
...
@@ -555,7 +555,7 @@ if(finishedOrder==null||finishedOrder.size()==0)
...
@@ -555,7 +555,7 @@ if(finishedOrder==null||finishedOrder.size()==0)
// Machine machine = machineIdMap.get(machineId);
// Machine machine = machineIdMap.get(machineId);
// int changeoverTime =0; //(lastDiscreteParameter.isEmpty() ||
// int changeoverTime =0; //(lastDiscreteParameter.isEmpty() ||
// lastDiscreteParameter.equals(currentOp.getDiscreteParameter())) ? 0 : 0;
// lastDiscreteParameter.equals(currentOp.getDiscreteParameter())) ? 0 : 0;
int
actualEndTime
=
processOperation
(
currentOp
,
machineId
,
processTime
,
machineOption
,
chromosome
,
machineIdMap
,
machineTasksCache
);
int
actualEndTime
=
processOperation
(
currentOp
,
machineId
,
processTime
,
machineOption
,
chromosome
,
machineIdMap
,
machineTasksCache
,
entryIndexById
,
scheduleIndexById
);
// int actualEndTime = processWithSingleMachine(currentOp, machine, processTime, prevtime,machineOption, chromosome,false,prevendtime,machineTasksCache);
// int actualEndTime = processWithSingleMachine(currentOp, machine, processTime, prevtime,machineOption, chromosome,false,prevendtime,machineTasksCache);
orderProcessCounter
.
put
(
groupId
,
orderProcessCounter
.
get
(
groupId
)
+
1
);
orderProcessCounter
.
put
(
groupId
,
orderProcessCounter
.
get
(
groupId
)
+
1
);
...
@@ -570,131 +570,7 @@ if(finishedOrder==null||finishedOrder.size()==0)
...
@@ -570,131 +570,7 @@ if(finishedOrder==null||finishedOrder.size()==0)
calculateScheduleResult
(
chromosome
);
calculateScheduleResult
(
chromosome
);
}
}
public
void
parallelDecode
(
Chromosome
chromosome
)
{
FileHelper
.
writeLogFile
(
"构建工序依赖图 _s"
);
// 1. 构建工序依赖图
Map
<
Integer
,
List
<
Integer
>>
dependencyGraph
=
buildDependencyGraph
(
chromosome
);
FileHelper
.
writeLogFile
(
"拓扑排序 _s"
);
// 2. 拓扑排序
List
<
Integer
>
topologicalOrder
=
topologicalSort
(
dependencyGraph
,
chromosome
);
FileHelper
.
writeLogFile
(
"按设备分组 _s"
);
// 3. 按设备分组
Map
<
Long
,
List
<
Integer
>>
machineToOpsMap
=
new
HashMap
<>();
Map
<
Integer
,
Integer
>
opToGroupIdMap
=
new
HashMap
<>();
Map
<
Integer
,
Long
>
opToMachineMap
=
new
HashMap
<>();
List
<
GlobalOperationInfo
>
globalOpList
=
chromosome
.
getGlobalOpList
();
// 步骤1:生成“工序→机器/加工时间”映射
List
<
OpMachine
>
opMachineMap
=
new
ArrayList
<>();
Map
<
String
,
OpMachine
>
opMachineKeyMap
=
new
HashMap
<>();
Map
<
Long
,
CopyOnWriteArrayList
<
GAScheduleResult
>>
machineTasksCache
=
new
HashMap
<>();
Map
<
Long
,
Machine
>
machineIdMap
=
chromosome
.
getMachines
().
stream
()
.
collect
(
Collectors
.
toMap
(
Machine:
:
getId
,
m
->
m
));
// 构建工序ID索引:opId -> Entry(O(1)查找)
Map
<
Integer
,
Entry
>
opIdIndex
=
buildOpIdIndex
(
chromosome
);
for
(
GlobalOperationInfo
globalOp
:
globalOpList
)
{
int
globalOpId
=
globalOp
.
getGlobalOpId
();
Entry
op
=
globalOp
.
getOp
();
int
groupId
=
globalOp
.
getGroupId
();
int
sequence
=
globalOp
.
getSequence
();
// 从MachineSelection中获取当前工序的机器选择顺序号
int
machineSeq
=
chromosome
.
getMachineSelection
().
get
(
globalOpId
);
List
<
MachineOption
>
optionalMachines
=
op
.
getMachineOptions
();
// 验证:机器顺序号必须在可选范围内
if
(
machineSeq
<
1
||
machineSeq
>
optionalMachines
.
size
())
{
throw
new
IllegalStateException
(
String
.
format
(
"全局工序%d(订单%d工序%d)的机器顺序号%d超出范围(1-%d)"
,
globalOpId
,
groupId
,
sequence
,
machineSeq
,
optionalMachines
.
size
()));
}
// 获取选择的设备ID和加工时间
MachineOption
selectedMachine
=
optionalMachines
.
get
(
machineSeq
-
1
);
OpMachine
opMachine
=
new
OpMachine
();
opMachine
.
setGroupId
(
groupId
);
opMachine
.
setSequence
(
sequence
);
opMachine
.
setMachineId
(
selectedMachine
.
getMachineId
());
opMachine
.
setProcessingTime
(
selectedMachine
.
getProcessingTime
());
opMachine
.
setRuntime
(
selectedMachine
.
getRuntime
());
opMachine
.
setSingleOut
(
selectedMachine
.
getSingleOut
());
opMachineMap
.
add
(
opMachine
);
String
key
=
opMachine
.
getGroupId
()
+
"_"
+
opMachine
.
getSequence
();
opMachineKeyMap
.
put
(
key
,
opMachine
);
}
FileHelper
.
writeLogFile
(
"预处理工序信息 _s"
);
// 预处理工序信息
for
(
int
opId
:
topologicalOrder
)
{
// Entry op = findOperationById(chromosome, opId);
Entry
op
=
opIdIndex
.
get
(
opId
);
if
(
op
!=
null
)
{
// 假设已经为工序分配了设备
String
opMachineKey
=
op
.
getGroupId
()
+
"_"
+
op
.
getSequence
();
OpMachine
machineOption
=
opMachineKeyMap
.
get
(
opMachineKey
);
if
(
machineOption
!=
null
)
{
machineToOpsMap
.
computeIfAbsent
(
machineOption
.
getMachineId
(),
k
->
new
ArrayList
<>()).
add
(
opId
);
opToGroupIdMap
.
put
(
opId
,
op
.
getGroupId
());
opToMachineMap
.
put
(
opId
,
machineOption
.
getMachineId
());
}
}
}
// 4. 并行处理
Map
<
Integer
,
CompletableFuture
<
Void
>>
opFutures
=
new
HashMap
<>();
Map
<
Long
,
CompletableFuture
<
Void
>>
machineFutures
=
new
HashMap
<>();
FileHelper
.
writeLogFile
(
"并行处理 _s"
);
for
(
int
opId
:
topologicalOrder
)
{
// 获取当前工序的依赖
// Entry op = findOperationById(chromosome, opId);
Entry
op
=
opIdIndex
.
get
(
opId
);
List
<
Integer
>
dependencies
=
dependencyGraph
.
getOrDefault
(
opId
,
Collections
.
emptyList
());
// 等待所有依赖完成
List
<
CompletableFuture
<
Void
>>
dependencyFutures
=
dependencies
.
stream
()
.
map
(
opFutures:
:
get
)
.
filter
(
Objects:
:
nonNull
)
.
collect
(
Collectors
.
toList
());
String
opMachineKey
=
op
.
getGroupId
()
+
"_"
+
op
.
getSequence
();
OpMachine
machineOption
=
opMachineKeyMap
.
get
(
opMachineKey
);
Long
machineId
=
machineOption
.
getMachineId
();
double
processTime
=
machineOption
.
getProcessingTime
();
// 等待当前设备的上一个工序完成
CompletableFuture
<
Void
>
machineFuture
=
machineFutures
.
getOrDefault
(
machineId
,
CompletableFuture
.
completedFuture
(
null
));
// 合并所有依赖
List
<
CompletableFuture
<
Void
>>
allDependencies
=
new
ArrayList
<>(
dependencyFutures
);
allDependencies
.
add
(
machineFuture
);
// 创建当前工序的处理任务
CompletableFuture
<
Void
>
currentFuture
=
CompletableFuture
.
allOf
(
allDependencies
.
toArray
(
new
CompletableFuture
[
0
]))
.
thenRunAsync
(()
->
{
// 处理当前工序
int
actualEndTime
=
processOperation
(
op
,
machineId
,
processTime
,
machineOption
,
chromosome
,
machineIdMap
,
machineTasksCache
);
});
// 保存当前工序的Future
opFutures
.
put
(
opId
,
currentFuture
);
// 更新设备的Future
machineFutures
.
put
(
machineId
,
currentFuture
);
}
// 等待所有工序完成
CompletableFuture
.
allOf
(
opFutures
.
values
().
toArray
(
new
CompletableFuture
[
0
])).
join
();
FileHelper
.
writeLogFile
(
"calculateScheduleResult _s"
);
if
(
chromosome
.
getReOrderids
()!=
null
&&
chromosome
.
getReOrderids
().
size
()>
0
)
{
chromosome
.
getOperationSequencing
().
removeIf
(
t
->
chromosome
.
getReOrderids
().
contains
(
t
));
}
calculateScheduleResult
(
chromosome
);
}
public
void
parallelDecodeByMachine
(
Chromosome
chromosome
)
{
public
void
parallelDecodeByMachine
(
Chromosome
chromosome
)
{
// 1. 获取工序处理顺序
// 1. 获取工序处理顺序
List
<
Integer
>
operationSequencing
=
chromosome
.
getOperationSequencing
();
List
<
Integer
>
operationSequencing
=
chromosome
.
getOperationSequencing
();
...
@@ -748,9 +624,15 @@ if(finishedOrder==null||finishedOrder.size()==0)
...
@@ -748,9 +624,15 @@ if(finishedOrder==null||finishedOrder.size()==0)
// 初始化订单处理计数器
// 初始化订单处理计数器
Map
<
Integer
,
Integer
>
orderProcessCounter
=
new
HashMap
<>();
Map
<
Integer
,
Integer
>
orderProcessCounter
=
new
HashMap
<>();
Map
<
Integer
,
Entry
>
entryIndexById
=
new
HashMap
<>();
Map
<
Integer
,
List
<
Entry
>>
entrysBygroupId
=
new
HashMap
<>();
Map
<
Integer
,
GAScheduleResult
>
scheduleIndexById
=
new
ConcurrentHashMap
<>();
for
(
Entry
op
:
allOperations
)
{
for
(
Entry
op
:
allOperations
)
{
int
groupId
=
op
.
getGroupId
();
int
groupId
=
op
.
getGroupId
();
orderProcessCounter
.
putIfAbsent
(
groupId
,
0
);
orderProcessCounter
.
putIfAbsent
(
groupId
,
0
);
entryIndexById
.
put
(
op
.
getId
(),
op
);
entrysBygroupId
.
computeIfAbsent
(
groupId
,
k
->
new
ArrayList
<>()).
add
(
op
);
}
}
Map
<
Long
,
List
<
Entry
>>
machineToOpsMap
=
new
HashMap
<>();
Map
<
Long
,
List
<
Entry
>>
machineToOpsMap
=
new
HashMap
<>();
//按照 OperationSequencing 顺序生成 machineToOpsMap
//按照 OperationSequencing 顺序生成 machineToOpsMap
...
@@ -886,11 +768,11 @@ if(finishedOrder==null||finishedOrder.size()==0)
...
@@ -886,11 +768,11 @@ if(finishedOrder==null||finishedOrder.size()==0)
// 工序超过500的设备直接在主线程串行处理
// 工序超过500的设备直接在主线程串行处理
if
(
ops
.
size
()
>
500
)
{
if
(
ops
.
size
()
>
500
)
{
// FileHelper.writeLogFile("设备 " + machineId + " 有 " + ops.size() + " 个工序,直接串行处理");
// FileHelper.writeLogFile("设备 " + machineId + " 有 " + ops.size() + " 个工序,直接串行处理");
processMachineOps
(
chromosome
,
machineId
,
ops
,
dependencyGraph
,
opCompleted
,
lock
,
opMachineKeyMap
,
machineIdMap
,
machineTasksCache
);
processMachineOps
(
chromosome
,
machineId
,
ops
,
dependencyGraph
,
opCompleted
,
lock
,
opMachineKeyMap
,
machineIdMap
,
machineTasksCache
,
entryIndexById
,
scheduleIndexById
);
}
else
{
}
else
{
// 工序少的设备创建线程处理
// 工序少的设备创建线程处理
Thread
thread
=
new
Thread
(()
->
{
Thread
thread
=
new
Thread
(()
->
{
processMachineOps
(
chromosome
,
machineId
,
ops
,
dependencyGraph
,
opCompleted
,
lock
,
opMachineKeyMap
,
machineIdMap
,
machineTasksCache
);
processMachineOps
(
chromosome
,
machineId
,
ops
,
dependencyGraph
,
opCompleted
,
lock
,
opMachineKeyMap
,
machineIdMap
,
machineTasksCache
,
entryIndexById
,
scheduleIndexById
);
});
});
thread
.
start
();
thread
.
start
();
threads
.
add
(
thread
);
threads
.
add
(
thread
);
...
@@ -920,7 +802,7 @@ if(finishedOrder==null||finishedOrder.size()==0)
...
@@ -920,7 +802,7 @@ if(finishedOrder==null||finishedOrder.size()==0)
*/
*/
private
void
processMachineOps
(
Chromosome
chromosome
,
Long
machineId
,
List
<
Entry
>
ops
,
private
void
processMachineOps
(
Chromosome
chromosome
,
Long
machineId
,
List
<
Entry
>
ops
,
Map
<
Integer
,
List
<
Integer
>>
dependencyGraph
,
Map
<
Integer
,
List
<
Integer
>>
dependencyGraph
,
Map
<
Integer
,
Boolean
>
opCompleted
,
Object
lock
,
Map
<
String
,
OpMachine
>
opMachineKeyMap
,
Map
<
Long
,
Machine
>
machineIdMap
,
Map
<
Long
,
CopyOnWriteArrayList
<
GAScheduleResult
>>
machineTasksCache
)
{
Map
<
Integer
,
Boolean
>
opCompleted
,
Object
lock
,
Map
<
String
,
OpMachine
>
opMachineKeyMap
,
Map
<
Long
,
Machine
>
machineIdMap
,
Map
<
Long
,
CopyOnWriteArrayList
<
GAScheduleResult
>>
machineTasksCache
,
Map
<
Integer
,
Entry
>
entryIndexById
,
Map
<
Integer
,
GAScheduleResult
>
scheduleIndexById
)
{
//long machineStartTime = System.currentTimeMillis();
//long machineStartTime = System.currentTimeMillis();
for
(
int
i
=
0
;
i
<
ops
.
size
();
i
++)
{
for
(
int
i
=
0
;
i
<
ops
.
size
();
i
++)
{
...
@@ -956,7 +838,7 @@ if(finishedOrder==null||finishedOrder.size()==0)
...
@@ -956,7 +838,7 @@ if(finishedOrder==null||finishedOrder.size()==0)
// 处理当前工序
// 处理当前工序
// long processStartTime = System.currentTimeMillis();
// long processStartTime = System.currentTimeMillis();
int
actualEndTime
=
processOperation
(
op
,
machineId
,
processTime
,
machineOption
,
chromosome
,
machineIdMap
,
machineTasksCache
);
int
actualEndTime
=
processOperation
(
op
,
machineId
,
processTime
,
machineOption
,
chromosome
,
machineIdMap
,
machineTasksCache
,
entryIndexById
,
scheduleIndexById
);
// long processEndTime = System.currentTimeMillis();
// long processEndTime = System.currentTimeMillis();
...
@@ -1114,7 +996,7 @@ if(finishedOrder==null||finishedOrder.size()==0)
...
@@ -1114,7 +996,7 @@ if(finishedOrder==null||finishedOrder.size()==0)
private
int
processOperation
(
Entry
currentOp
,
Long
machineId
,
double
processTime
,
OpMachine
machineOption
,
Chromosome
chromosome
,
Map
<
Long
,
Machine
>
machineIdMap
,
Map
<
Long
,
CopyOnWriteArrayList
<
GAScheduleResult
>>
machineTasksCache
)
private
int
processOperation
(
Entry
currentOp
,
Long
machineId
,
double
processTime
,
OpMachine
machineOption
,
Chromosome
chromosome
,
Map
<
Long
,
Machine
>
machineIdMap
,
Map
<
Long
,
CopyOnWriteArrayList
<
GAScheduleResult
>>
machineTasksCache
,
Map
<
Integer
,
Entry
>
entryIndexById
,
Map
<
Integer
,
GAScheduleResult
>
scheduleIndexById
)
{
{
Machine
targetMachine
=
machineIdMap
.
get
(
machineId
);
Machine
targetMachine
=
machineIdMap
.
get
(
machineId
);
...
@@ -1123,7 +1005,7 @@ if(finishedOrder==null||finishedOrder.size()==0)
...
@@ -1123,7 +1005,7 @@ if(finishedOrder==null||finishedOrder.size()==0)
int
teardownTime
=
currentOp
.
getTeardownTime
();
int
teardownTime
=
currentOp
.
getTeardownTime
();
if
(!
currentOp
.
getPrevEntryIds
().
isEmpty
())
{
if
(!
currentOp
.
getPrevEntryIds
().
isEmpty
())
{
// 处理多个前工序
// 处理多个前工序
prevtime
=
CalPrevtime
(
prevtime
,
currentOp
,
chromosome
,
processTime
,
targetMachine
);
prevtime
=
CalPrevtime
(
prevtime
,
currentOp
,
chromosome
,
processTime
,
targetMachine
,
entryIndexById
,
scheduleIndexById
);
}
}
int
bomtime
=
getOperationBOMTime
(
currentOp
,
chromosome
);
int
bomtime
=
getOperationBOMTime
(
currentOp
,
chromosome
);
...
@@ -1131,14 +1013,14 @@ if(finishedOrder==null||finishedOrder.size()==0)
...
@@ -1131,14 +1013,14 @@ if(finishedOrder==null||finishedOrder.size()==0)
int
prevendtime
=
prevtime
;
int
prevendtime
=
prevtime
;
prevtime
=
Math
.
max
(
prevtime
,
bomtime
);
prevtime
=
Math
.
max
(
prevtime
,
bomtime
);
Machine
machine
=
machineIdMap
.
get
(
machineId
);
Machine
machine
=
machineIdMap
.
get
(
machineId
);
int
actualEndTime
=
processWithSingleMachine
(
currentOp
,
machine
,
processTime
,
prevtime
,
machineOption
,
chromosome
,
false
,
prevendtime
,
machineTasksCache
);
int
actualEndTime
=
processWithSingleMachine
(
currentOp
,
machine
,
processTime
,
prevtime
,
machineOption
,
chromosome
,
false
,
prevendtime
,
machineTasksCache
,
entryIndexById
,
scheduleIndexById
);
return
actualEndTime
;
return
actualEndTime
;
}
}
private
int
processWithSingleMachine
(
Entry
operation
,
Machine
machine
,
double
processingTime
,
private
int
processWithSingleMachine
(
Entry
operation
,
Machine
machine
,
double
processingTime
,
int
prevOperationEndTime
,
OpMachine
machineOption
,
Chromosome
chromosome
,
boolean
calbom
,
int
prevendtime
,
Map
<
Long
,
CopyOnWriteArrayList
<
GAScheduleResult
>>
machineTasksCache
)
{
int
prevOperationEndTime
,
OpMachine
machineOption
,
Chromosome
chromosome
,
boolean
calbom
,
int
prevendtime
,
Map
<
Long
,
CopyOnWriteArrayList
<
GAScheduleResult
>>
machineTasksCache
,
Map
<
Integer
,
Entry
>
entryIndexById
,
Map
<
Integer
,
GAScheduleResult
>
scheduleIndexById
)
{
int
processingTimeTotal
=
0
;
int
processingTimeTotal
=
0
;
int
earliestStartTime
=
prevOperationEndTime
;
int
earliestStartTime
=
prevOperationEndTime
;
if
(
operation
.
getConstTime
()==
1
)
//常数时间
if
(
operation
.
getConstTime
()==
1
)
//常数时间
...
@@ -1239,7 +1121,7 @@ return actualEndTime;
...
@@ -1239,7 +1121,7 @@ return actualEndTime;
:
earliestStartTime
;
:
earliestStartTime
;
}
}
bomtime
=
EditOperationBOMTime
(
operation
,
chromosome
,
earliestStartTime
,
machineTasksCache
);
bomtime
=
EditOperationBOMTime
(
operation
,
chromosome
,
earliestStartTime
,
machineTasksCache
,
entryIndexById
,
scheduleIndexById
);
if
(
bomtime
>
prevendtime
&&
bomtime
<
earliestStartTimeold
)
if
(
bomtime
>
prevendtime
&&
bomtime
<
earliestStartTimeold
)
...
@@ -1394,7 +1276,7 @@ return actualEndTime;
...
@@ -1394,7 +1276,7 @@ return actualEndTime;
if
(
machineTasks
!=
null
)
{
if
(
machineTasks
!=
null
)
{
machineTasks
.
add
(
result
);
machineTasks
.
add
(
result
);
}
}
scheduleIndexById
.
put
(
operation
.
getId
(),
result
);
return
endTime
;
return
endTime
;
}
}
...
@@ -1405,16 +1287,18 @@ return actualEndTime;
...
@@ -1405,16 +1287,18 @@ return actualEndTime;
* @param chromosome
* @param chromosome
* @return
* @return
*/
*/
private
int
CalPrevtime
(
int
prevtime
,
Entry
currentOp
,
Chromosome
chromosome
,
double
processTime
,
Machine
machine
)
{
private
int
CalPrevtime
(
int
prevtime
,
Entry
currentOp
,
Chromosome
chromosome
,
double
processTime
,
Machine
machine
,
Map
<
Integer
,
Entry
>
entryIndexById
,
Map
<
Integer
,
GAScheduleResult
>
scheduleIndexById
)
{
List
<
OperationDependency
>
FsOperations
=
currentOp
.
getPrevEntryIds
().
stream
()
List
<
OperationDependency
>
FsOperations
=
currentOp
.
getPrevEntryIds
().
stream
()
.
filter
(
t
->
t
.
getDependencyType
()
==
DependencyType
.
FinishToStart
)
.
filter
(
t
->
t
.
getDependencyType
()
==
DependencyType
.
FinishToStart
)
.
collect
(
Collectors
.
toList
());
//串行
.
collect
(
Collectors
.
toList
());
//串行
if
(
FsOperations
!=
null
&&
FsOperations
.
size
()
>
0
)
{
if
(
FsOperations
!=
null
&&
FsOperations
.
size
()
>
0
)
{
for
(
OperationDependency
opid
:
FsOperations
)
{
for
(
OperationDependency
opid
:
FsOperations
)
{
List
<
GAScheduleResult
>
prevOperations
=
chromosome
.
getResult
().
stream
()
// List<GAScheduleResult> prevOperations = chromosome.getResult().stream()
.
filter
(
t
->
t
.
getGroupId
()
==
currentOp
.
getGroupId
()
&&
t
.
getOperationId
()
==
opid
.
getPrevOperationId
())
// .filter(t -> t.getOperationId() == opid.getPrevOperationId())
.
collect
(
Collectors
.
toList
());
//多台
// .collect(Collectors.toList());//
for
(
GAScheduleResult
prevOp
:
prevOperations
)
{
GAScheduleResult
prevOp
=
scheduleIndexById
.
get
(
opid
.
getPrevOperationId
());
// for (GAScheduleResult prevOp : prevOperations) {
if
(
prevOp
!=
null
){
//加上后处理时间
//加上后处理时间
prevtime
=
Math
.
max
(
prevtime
,
prevOp
.
getEndTime
()
+
currentOp
.
getTeardownTime
());
prevtime
=
Math
.
max
(
prevtime
,
prevOp
.
getEndTime
()
+
currentOp
.
getTeardownTime
());
}
}
...
@@ -1431,10 +1315,13 @@ return actualEndTime;
...
@@ -1431,10 +1315,13 @@ return actualEndTime;
for
(
int
j
=
0
;
j
<
SSOperations
.
size
();
j
++)
for
(
int
j
=
0
;
j
<
SSOperations
.
size
();
j
++)
{
{
OperationDependency
opid
=
SSOperations
.
get
(
j
);
OperationDependency
opid
=
SSOperations
.
get
(
j
);
List
<
GAScheduleResult
>
prevOperations
=
chromosome
.
getResult
().
stream
()
// List<GAScheduleResult> prevOperations = chromosome.getResult().stream()
.
filter
(
t
->
t
.
getGroupId
()
==
currentOp
.
getGroupId
()
&&
t
.
getOperationId
()
==
opid
.
getPrevOperationId
())
// .filter(t -> t.getOperationId() == opid.getPrevOperationId())
.
collect
(
Collectors
.
toList
());
//多台
// .collect(Collectors.toList());//多台
for
(
GAScheduleResult
prevOp
:
prevOperations
)
{
GAScheduleResult
prevOp
=
scheduleIndexById
.
get
(
opid
.
getPrevOperationId
());
// for (GAScheduleResult prevOp : prevOperations) {
if
(
prevOp
!=
null
){
newScheduleResult
.
add
(
prevOp
);
newScheduleResult
.
add
(
prevOp
);
newScheduleResultDetails
.
addAll
(
prevOp
.
getGeneDetails
());
newScheduleResultDetails
.
addAll
(
prevOp
.
getGeneDetails
());
}
}
...
@@ -1444,15 +1331,17 @@ return actualEndTime;
...
@@ -1444,15 +1331,17 @@ return actualEndTime;
prevtime
=
Math
.
max
(
prevtime
,
prevtime1
);
prevtime
=
Math
.
max
(
prevtime
,
prevtime1
);
}
else
{
}
else
{
Entry
entry
=
chromosome
.
getAllOperations
().
stream
()
// Entry entry= chromosome.getAllOperations().stream()
.
filter
(
t
->
t
.
getId
()==
opid
.
getPrevOperationId
())
// .filter(t->t.getId()==opid.getPrevOperationId())
.
findFirst
().
orElse
(
null
);
// .findFirst().orElse(null);
Entry
entry
=
entryIndexById
.
get
(
opid
.
getPrevOperationId
());
OperationDependency
opid2
=
SSOperations
.
get
(
j
+
1
);
OperationDependency
opid2
=
SSOperations
.
get
(
j
+
1
);
Entry
entry1
=
chromosome
.
getAllOperations
().
stream
()
// Entry entry1= chromosome.getAllOperations().stream()
.
filter
(
t
->
t
.
getId
()==
opid2
.
getPrevOperationId
())
// .filter(t->t.getId()==opid2.getPrevOperationId())
.
findFirst
().
orElse
(
null
);
// .findFirst().orElse(null);
Entry
entry1
=
entryIndexById
.
get
(
opid2
.
getPrevOperationId
());
if
(
entry
.
getRoutingDetailId
()!=
entry1
.
getRoutingDetailId
())
//不是同一前工序,效率不能合并 newScheduleResult 清空,如何是一个工序就合并计算
if
(
entry
!=
null
&&
entry1
!=
null
&&
entry
.
getRoutingDetailId
()!=
entry1
.
getRoutingDetailId
())
{
{
int
prevtime1
=
CalSSPrevtime
(
newScheduleResult
,
newScheduleResultDetails
,
prevtime
,
currentOp
,
chromosome
,
processTime
,
machine
);
int
prevtime1
=
CalSSPrevtime
(
newScheduleResult
,
newScheduleResultDetails
,
prevtime
,
currentOp
,
chromosome
,
processTime
,
machine
);
...
@@ -1577,7 +1466,7 @@ return actualEndTime;
...
@@ -1577,7 +1466,7 @@ return actualEndTime;
return
Math
.
max
(
rawTime
,
sfTime
);
return
Math
.
max
(
rawTime
,
sfTime
);
}
}
private
int
EditOperationBOMTime
(
Entry
currentOp
,
Chromosome
chromosome
,
int
earliestStartTime
,
Map
<
Long
,
CopyOnWriteArrayList
<
GAScheduleResult
>>
machineTasksCache
)
{
private
int
EditOperationBOMTime
(
Entry
currentOp
,
Chromosome
chromosome
,
int
earliestStartTime
,
Map
<
Long
,
CopyOnWriteArrayList
<
GAScheduleResult
>>
machineTasksCache
,
Map
<
Integer
,
Entry
>
entryIndexById
,
Map
<
Integer
,
GAScheduleResult
>
scheduleIndexById
)
{
List
<
OrderMaterialRequirement
>
opboms
=
currentOp
.
getMaterialRequirements
();
List
<
OrderMaterialRequirement
>
opboms
=
currentOp
.
getMaterialRequirements
();
...
@@ -1585,13 +1474,13 @@ return actualEndTime;
...
@@ -1585,13 +1474,13 @@ return actualEndTime;
{
{
return
0
;
return
0
;
}
}
LocalDateTime
earliestStartTime1
=
baseTime
.
plusSeconds
(
earliestStartTime
);
LocalDateTime
earliestStartTime1
=
baseTime
.
plusSeconds
(
earliestStartTime
);
materialRequirementService
.
EditOperationBOM
(
currentOp
,
chromosome
,
earliestStartTime1
,
this
,
machineTasksCache
);
materialRequirementService
.
EditOperationBOM
(
currentOp
,
chromosome
,
earliestStartTime1
,
this
,
machineTasksCache
,
entryIndexById
,
scheduleIndexById
,
baseTime
);
return
getOperationBOMTime
(
currentOp
,
chromosome
);
return
getOperationBOMTime
(
currentOp
,
chromosome
);
}
}
public
void
EditorderOperation
(
Chromosome
chromosome
,
int
groupId
,
double
needed
,
Map
<
Long
,
CopyOnWriteArrayList
<
GAScheduleResult
>>
machineTasksCache
){
public
void
EditorderOperation
(
Chromosome
chromosome
,
int
groupId
,
double
needed
,
Map
<
Long
,
CopyOnWriteArrayList
<
GAScheduleResult
>>
machineTasksCache
,
Map
<
Integer
,
Entry
>
entryIndexById
,
Map
<
Integer
,
GAScheduleResult
>
scheduleIndexById
){
List
<
Entry
>
orderOps
=
chromosome
.
getAllOperations
().
stream
()
List
<
Entry
>
orderOps
=
chromosome
.
getAllOperations
().
stream
()
.
filter
(
t
->
t
.
getGroupId
()
==
groupId
)
.
filter
(
t
->
t
.
getGroupId
()
==
groupId
)
.
sorted
(
Comparator
.
comparing
(
Entry:
:
getSequence
))
.
sorted
(
Comparator
.
comparing
(
Entry:
:
getSequence
))
...
@@ -1635,7 +1524,7 @@ return getOperationBOMTime(currentOp, chromosome);
...
@@ -1635,7 +1524,7 @@ return getOperationBOMTime(currentOp, chromosome);
int
teardownTime
=
currentOp
.
getTeardownTime
();
int
teardownTime
=
currentOp
.
getTeardownTime
();
if
(!
currentOp
.
getPrevEntryIds
().
isEmpty
())
{
if
(!
currentOp
.
getPrevEntryIds
().
isEmpty
())
{
// 处理多个前工序
// 处理多个前工序
prevtime
=
CalPrevtime
(
prevtime
,
currentOp
,
chromosome
,
processTime
,
targetMachine
);
prevtime
=
CalPrevtime
(
prevtime
,
currentOp
,
chromosome
,
processTime
,
targetMachine
,
entryIndexById
,
scheduleIndexById
);
}
}
// 上个离散参数
// 上个离散参数
...
@@ -1650,7 +1539,7 @@ return getOperationBOMTime(currentOp, chromosome);
...
@@ -1650,7 +1539,7 @@ return getOperationBOMTime(currentOp, chromosome);
.
findFirst
()
.
findFirst
()
.
orElse
(
null
);
.
orElse
(
null
);
// 缓存机器任务
// 缓存机器任务
int
actualEndTime
=
processWithSingleMachine
(
currentOp
,
machine
,
processTime
,
prevtime
,
opMachine
,
chromosome
,
true
,
prevendtime
,
machineTasksCache
);
int
actualEndTime
=
processWithSingleMachine
(
currentOp
,
machine
,
processTime
,
prevtime
,
opMachine
,
chromosome
,
true
,
prevendtime
,
machineTasksCache
,
entryIndexById
,
scheduleIndexById
);
}
}
...
@@ -1687,10 +1576,10 @@ return getOperationBOMTime(currentOp, chromosome);
...
@@ -1687,10 +1576,10 @@ return getOperationBOMTime(currentOp, chromosome);
&&
t
.
getProductOrderID
()
!=
null
&&
!
t
.
getProductOrderID
().
isEmpty
()
&&
t
.
getProductOrderID
()
!=
null
&&
!
t
.
getProductOrderID
().
isEmpty
()
)
)
.
collect
(
Collectors
.
toList
());
.
collect
(
Collectors
.
toList
());
if
(
MaterialRequirements
==
null
||
MaterialRequirements
.
size
()==
0
)
if
(
MaterialRequirements
==
null
||
MaterialRequirements
.
size
()==
0
)
{
{
continue
;
continue
;
}
}
for
(
OrderMaterialRequirement
orderMaterial:
MaterialRequirements
)
{
for
(
OrderMaterialRequirement
orderMaterial:
MaterialRequirements
)
{
List
<
Integer
>
orderids
=
orderMaterial
.
getProductOrderID
();
List
<
Integer
>
orderids
=
orderMaterial
.
getProductOrderID
();
if
(
orderids
!=
null
&&
orderids
.
size
()>
0
)
{
if
(
orderids
!=
null
&&
orderids
.
size
()>
0
)
{
...
@@ -2443,7 +2332,7 @@ if(MaterialRequirements==null||MaterialRequirements.size()==0)
...
@@ -2443,7 +2332,7 @@ if(MaterialRequirements==null||MaterialRequirements.size()==0)
.
filter
(
t
->
orderIds
.
contains
(
t
.
getOrderId
()))
.
filter
(
t
->
orderIds
.
contains
(
t
.
getOrderId
()))
.
max
(
Comparator
.
comparing
(
Order:
:
getDueDate
))
.
max
(
Comparator
.
comparing
(
Order:
:
getDueDate
))
.
orElse
(
null
);
.
orElse
(
null
);
if
(
order
.
isNewCreate
())
{
if
(
order
.
isNew
Sf
Create
())
{
continue
;
continue
;
}
}
LocalDateTime
dueDateTime
=
order
.
getDueDate
();
LocalDateTime
dueDateTime
=
order
.
getDueDate
();
...
...
src/main/java/com/aps/service/Algorithm/GeneticOperations.java
View file @
f2a1529b
...
@@ -25,6 +25,10 @@ public class GeneticOperations {
...
@@ -25,6 +25,10 @@ public class GeneticOperations {
private
static
ScheduleParams
param
;
private
static
ScheduleParams
param
;
public
GeneticOperations
()
{
}
public
GeneticOperations
(
GlobalParam
globalParam
,
List
<
Entry
>
_allOperations
,
ScheduleParams
_param
)
{
public
GeneticOperations
(
GlobalParam
globalParam
,
List
<
Entry
>
_allOperations
,
ScheduleParams
_param
)
{
_GlobalParam
=
globalParam
;
_GlobalParam
=
globalParam
;
allOperations
=
_allOperations
;
allOperations
=
_allOperations
;
...
@@ -424,10 +428,12 @@ public class GeneticOperations {
...
@@ -424,10 +428,12 @@ public class GeneticOperations {
public
void
DelOrder
(
Chromosome
chromosome
)
{
public
void
DelOrder
(
Chromosome
chromosome
)
{
List
<
Entry
>
allOperations
=
chromosome
.
getAllOperations
();
List
<
Entry
>
allOperations
=
chromosome
.
getAllOperations
();
List
<
GlobalOperationInfo
>
globalOpList
=
chromosome
.
getGlobalOpList
();
List
<
GlobalOperationInfo
>
globalOpList
=
chromosome
.
getGlobalOpList
();
if
(
chromosome
.
getOrders
()==
null
||
chromosome
.
getOrders
().
size
()==
0
)
return
;
List
<
Order
>
orders
=
chromosome
.
getOrders
();
List
<
Order
>
orders
=
chromosome
.
getOrders
();
List
<
Integer
>
OperationSequencing
=
chromosome
.
getOperationSequencing
();
List
<
Integer
>
OperationSequencing
=
chromosome
.
getOperationSequencing
();
List
<
Integer
>
newoorderids
=
orders
.
stream
()
List
<
Integer
>
newoorderids
=
orders
.
stream
()
.
filter
(
t
->
t
.
isNewCreate
())
.
filter
(
t
->
t
.
isNew
Sf
Create
())
.
map
(
Order:
:
getId
)
.
map
(
Order:
:
getId
)
.
sorted
(
Comparator
.
reverseOrder
())
.
sorted
(
Comparator
.
reverseOrder
())
.
collect
(
Collectors
.
toList
());
.
collect
(
Collectors
.
toList
());
...
...
src/main/java/com/aps/service/Algorithm/HillClimbing.java
View file @
f2a1529b
package
com
.
aps
.
service
.
Algorithm
;
package
com
.
aps
.
service
.
Algorithm
;
import
com.aps.common.util.FileHelper
;
import
com.aps.common.util.FileHelper
;
import
com.aps.common.util.GlobalCacheUtil
;
import
com.aps.common.util.ProductionDeepCopyUtil
;
import
com.aps.common.util.ProductionDeepCopyUtil
;
import
com.aps.entity.Algorithm.*
;
import
com.aps.entity.Algorithm.*
;
import
com.aps.entity.Algorithm.IDAndChildID.GroupResult
;
import
com.aps.entity.Algorithm.IDAndChildID.GroupResult
;
...
@@ -21,6 +22,11 @@ public class HillClimbing {
...
@@ -21,6 +22,11 @@ public class HillClimbing {
private
List
<
Entry
>
allOperations
;
private
List
<
Entry
>
allOperations
;
private
List
<
Order
>
orders
;
private
List
<
Material
>
materials
;
private
List
<
GroupResult
>
_entryRel
;
//按优先级分组工序
//按优先级分组工序
private
Map
<
Double
,
List
<
Entry
>>
priorityGroups
;
private
Map
<
Double
,
List
<
Entry
>>
priorityGroups
;
...
@@ -30,10 +36,17 @@ public class HillClimbing {
...
@@ -30,10 +36,17 @@ public class HillClimbing {
// 从List转为Map op.getGroupId() + "_" + op.getSequence(); 做主键
// 从List转为Map op.getGroupId() + "_" + op.getSequence(); 做主键
private
Map
<
String
,
Entry
>
entrys
;
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
.
allOperations
=
allOperations
;
this
.
orders
=
orders
;
this
.
materials
=
materials
;
_entryRel
=
entryRel
;
fitnessCalculator
=
_fitnessCalculator
;
// 按优先级分组工序
// 按优先级分组工序
priorityGroups
=
groupOperationsByPriority
();
priorityGroups
=
groupOperationsByPriority
();
...
@@ -92,7 +105,7 @@ public class HillClimbing {
...
@@ -92,7 +105,7 @@ public class HillClimbing {
Chromosome
machineChange
=
generateMachineChange
(
current
,
op
.
getMachineOptions
(),
maPos
);
Chromosome
machineChange
=
generateMachineChange
(
current
,
op
.
getMachineOptions
(),
maPos
);
if
(
machineChange
!=
null
)
{
if
(
machineChange
!=
null
)
{
decode
(
decoder
,
machineChange
);
decode
(
decoder
,
machineChange
,
machines
);
if
(
isBetter
(
machineChange
,
current
))
{
if
(
isBetter
(
machineChange
,
current
))
{
current
=
machineChange
;
current
=
machineChange
;
if
(
isBetter
(
current
,
best
))
{
if
(
isBetter
(
current
,
best
))
{
...
@@ -263,7 +276,7 @@ public class HillClimbing {
...
@@ -263,7 +276,7 @@ public class HillClimbing {
Chromosome
machineChange
=
generateMachineChange
(
current
,
op
.
getMachineOptions
(),
maPos
);
Chromosome
machineChange
=
generateMachineChange
(
current
,
op
.
getMachineOptions
(),
maPos
);
if
(
machineChange
!=
null
)
{
if
(
machineChange
!=
null
)
{
decode
(
decoder
,
machineChange
);
decode
(
decoder
,
machineChange
,
machines
);
if
(
isBetter
(
machineChange
,
current
))
{
if
(
isBetter
(
machineChange
,
current
))
{
current
=
machineChange
;
current
=
machineChange
;
if
(
isBetter
(
current
,
best
))
{
if
(
isBetter
(
current
,
best
))
{
...
@@ -328,7 +341,7 @@ public class HillClimbing {
...
@@ -328,7 +341,7 @@ public class HillClimbing {
}
}
Chromosome
newChromosome
=
swapAtDistance
(
current
,
opPos
,
-
s
*
step
);
Chromosome
newChromosome
=
swapAtDistance
(
current
,
opPos
,
-
s
*
step
);
decode
(
decoder
,
newChromosome
);
decode
(
decoder
,
newChromosome
,
machines
);
if
(
isBetter
(
newChromosome
,
current
))
{
if
(
isBetter
(
newChromosome
,
current
))
{
current
=
newChromosome
;
current
=
newChromosome
;
...
@@ -357,7 +370,7 @@ public class HillClimbing {
...
@@ -357,7 +370,7 @@ public class HillClimbing {
}
}
Chromosome
newChromosome
=
swapAtDistance
(
current
,
opPos
,
s
*
step
);
Chromosome
newChromosome
=
swapAtDistance
(
current
,
opPos
,
s
*
step
);
decode
(
decoder
,
newChromosome
);
decode
(
decoder
,
newChromosome
,
machines
);
if
(
isBetter
(
newChromosome
,
current
))
{
if
(
isBetter
(
newChromosome
,
current
))
{
current
=
newChromosome
;
current
=
newChromosome
;
...
@@ -411,21 +424,24 @@ public class HillClimbing {
...
@@ -411,21 +424,24 @@ public class HillClimbing {
}
}
private
void
writeKpi
(
Chromosome
chromosome
)
{
/**
String
fitness
=
""
;
* 构建位置索引:groupId_sequence -> position
*/
private
Map
<
String
,
Integer
>
buildPositionIndex
(
Chromosome
chromosome
)
{
String
fitness
=
""
;
double
[]
fitness1
=
chromosome
.
getFitnessLevel
();
double
[]
fitness1
=
chromosome
.
getFitnessLevel
();
for
(
int
i
=
0
;
i
<
fitness1
.
length
;
i
++)
{
for
(
int
i
=
0
;
i
<
fitness1
.
length
;
i
++)
{
fitness
+=
fitness1
[
i
]+
","
;
fitness
+=
fitness1
[
i
]
+
","
;
}
}
FileHelper
.
writeLogFile
(
String
.
format
(
"爬山法 - kpi:%s"
,
fitness
));
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
<>();
Map
<
String
,
Integer
>
index
=
new
HashMap
<>();
List
<
Integer
>
os
=
chromosome
.
getOperationSequencing
();
List
<
Integer
>
os
=
chromosome
.
getOperationSequencing
();
...
@@ -546,114 +562,6 @@ public class HillClimbing {
...
@@ -546,114 +562,6 @@ public class HillClimbing {
}
}
return
neighbor
;
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 {
...
@@ -703,11 +611,34 @@ public class HillClimbing {
/**
/**
* 解码染色体
* 解码染色体
*/
*/
private
void
decode
(
GeneticDecoder
decoder
,
Chromosome
chromosome
)
{
private
void
decode
(
GeneticDecoder
decoder
,
Chromosome
chromosome
,
List
<
Machine
>
machines
)
{
// chromosome.setResult(new java.util.concurrent.CopyOnWriteArrayList<>());
chromosome
.
setResult
(
new
CopyOnWriteArrayList
<>());
decoder
.
decodeChromosomeWithCache
(
chromosome
);
// 假设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 @
f2a1529b
package
com
.
aps
.
service
.
Algorithm
;
package
com
.
aps
.
service
.
Algorithm
;
import
com.aps.common.util.DateTimeUtil
;
import
com.aps.common.util.*
;
import
com.aps.common.util.DeepCopyUtil
;
import
com.aps.entity.Algorithm.*
;
import
com.aps.common.util.FileHelper
;
import
com.aps.common.util.ProductionDeepCopyUtil
;
import
com.aps.entity.Algorithm.*
;
import
com.aps.entity.Algorithm.IDAndChildID.GroupResult
;
import
com.aps.entity.Algorithm.IDAndChildID.GroupResult
;
import
com.aps.entity.basic.*
;
import
com.aps.entity.basic.*
;
import
com.aps.service.plan.MachineSchedulerService
;
import
com.aps.service.plan.MachineSchedulerService
;
...
@@ -55,11 +52,11 @@ public class HybridAlgorithm {
...
@@ -55,11 +52,11 @@ public class HybridAlgorithm {
// 初始化算法实例
// 初始化算法实例
private
HillClimbing
_hillClimbing
;
private
HillClimbing
_hillClimbing
;
private
SimulatedAnnealing
_simulatedAnnealing
;
private
SimulatedAnnealing
_simulatedAnnealing
;
private
ParallelLocalSearch
_parallelLocalSearch
;
// 初始化算法实例
// 初始化算法实例
private
TabuSearch
_tabuSearch
;
private
TabuSearch
_tabuSearch
;
private
TabuSearchWithSA
_tabuSearchWithSA
;
public
HybridAlgorithm
(
GlobalParam
globalParam
,
List
<
Machine
>
machines
,
List
<
Order
>
orders
,
public
HybridAlgorithm
(
GlobalParam
globalParam
,
List
<
Machine
>
machines
,
List
<
Order
>
orders
,
...
@@ -109,18 +106,16 @@ int opcount=allOperations.size();
...
@@ -109,18 +106,16 @@ int opcount=allOperations.size();
// 预生成全局工序列表(所有初始化方法共享同一顺序)
// 预生成全局工序列表(所有初始化方法共享同一顺序)
List
<
GlobalOperationInfo
>
globalOpList
=
initialization
.
generateGlobalOpList
();
List
<
GlobalOperationInfo
>
globalOpList
=
initialization
.
generateGlobalOpList
();
// 初始化变邻域搜索
// 初始化变邻域搜索
_vns
=
new
VariableNeighborhoodSearch
(
_GlobalParam
,
allOperations
,
globalOpList
,
_fitnessCalculator
,
_objectiveWeights
);
_vns
=
new
VariableNeighborhoodSearch
(
allOperations
,
orders
,
materials
,
_entryRel
,
_fitnessCalculator
);
_hillClimbing
=
new
HillClimbing
(
allOperations
);
_hillClimbing
=
new
HillClimbing
(
allOperations
,
orders
,
materials
,
_entryRel
,
_fitnessCalculator
);
_simulatedAnnealing
=
new
SimulatedAnnealing
(
allOperations
);
_simulatedAnnealing
=
new
SimulatedAnnealing
(
allOperations
,
orders
,
materials
,
_entryRel
,
_fitnessCalculator
);
_parallelLocalSearch
=
new
ParallelLocalSearch
(
_GlobalParam
,
allOperations
,
globalOpList
,
_fitnessCalculator
,
_objectiveWeights
);
_tabuSearch
=
new
TabuSearch
(
allOperations
,
orders
,
materials
,
_entryRel
,
_fitnessCalculator
);
_tabuSearch
=
new
TabuSearch
(
_GlobalParam
,
allOperations
,
globalOpList
,
_fitnessCalculator
,
_objectiveWeights
);
_tabuSearchWithSA
=
new
TabuSearchWithSA
(
_GlobalParam
,
allOperations
,
globalOpList
,
_fitnessCalculator
,
_objectiveWeights
);
FileHelper
.
writeLogFile
(
"初始化种群-----------开始-------"
);
FileHelper
.
writeLogFile
(
"初始化种群-----------开始-------"
);
// 步骤1:使用构造启发式算法生成初始种群
// 步骤1:使用构造启发式算法生成初始种群
FileHelper
.
writeLogFile
(
"构造启发式初始化-----------开始-------"
);
FileHelper
.
writeLogFile
(
"构造启发式初始化-----------开始-------"
);
List
<
Chromosome
>
population
=
initialization
.
generateHeuristicInitialPopulation
(
param
,
globalOpList
);
List
<
Chromosome
>
population
=
initialization
.
generateHeuristicInitialPopulation
(
param
);
FileHelper
.
writeLogFile
(
"构造启发式初始化-----------结束-------"
);
FileHelper
.
writeLogFile
(
"构造启发式初始化-----------结束-------"
);
...
@@ -138,15 +133,15 @@ int opcount=allOperations.size();
...
@@ -138,15 +133,15 @@ int opcount=allOperations.size();
FileHelper
.
writeLogFile
(
"按Objectives去重-----------开始-------"
+
population
.
size
());
FileHelper
.
writeLogFile
(
"按Objectives去重-----------开始-------"
+
population
.
size
());
population
=
chromosomeDistinctByObjectives
(
population
);
population
=
chromosomeDistinctByObjectives
(
population
);
FileHelper
.
writeLogFile
(
"按Objectives去重-----------结束-------"
+
population
.
size
());
FileHelper
.
writeLogFile
(
"按Objectives去重-----------结束-------"
+
population
.
size
());
// if(1==1)
// return getBestChromosome(population.get(0), param.getBaseTime(), starttime);
// 步骤2:对初始种群进行爬山法局部优化
// 步骤2:对初始种群进行爬山法局部优化
if
(
opcount
<
20
)
{
if
(
opcount
<
20
)
{
FileHelper
.
writeLogFile
(
"爬山法局部优化-----------开始-------"
);
FileHelper
.
writeLogFile
(
"爬山法局部优化-----------开始-------"
);
GeneticDecoder
hillClimbingDecoder
=
new
GeneticDecoder
(
_GlobalParam
,
param
.
getBaseTime
(),
machines
,
orders
,
materials
,
machineScheduler
,
materialRequirementService
,
sceneId
);
GeneticDecoder
hillClimbingDecoder
=
new
GeneticDecoder
(
_GlobalParam
,
param
.
getBaseTime
(),
machines
,
orders
,
materials
,
machineScheduler
,
materialRequirementService
,
sceneId
);
Chromosome
optimized
=
_hillClimbing
.
BatchSearchAll
(
population
,
machines
,
hillClimbingDecoder
);
Chromosome
optimized
=
_hillClimbing
.
search
(
population
.
get
(
0
),
hillClimbingDecoder
,
machines
);
FileHelper
.
writeLogFile
(
"爬山法局部优化-----------结束-------"
);
FileHelper
.
writeLogFile
(
"爬山法局部优化-----------结束-------"
);
return
getBestChromosome
(
optimized
,
param
.
getBaseTime
(),
starttime
);
return
getBestChromosome
(
optimized
,
param
.
getBaseTime
(),
starttime
);
}
}
...
@@ -156,27 +151,37 @@ int opcount=allOperations.size();
...
@@ -156,27 +151,37 @@ int opcount=allOperations.size();
// 步骤2:对初始种群进行模拟退火+爬山法优化
// 步骤2:对初始种群进行模拟退火+爬山法优化
GeneticDecoder
saDecoder1
=
new
GeneticDecoder
(
_GlobalParam
,
param
.
getBaseTime
(),
machines
,
orders
,
materials
,
machineScheduler
,
materialRequirementService
,
sceneId
);
GeneticDecoder
saDecoder1
=
new
GeneticDecoder
(
_GlobalParam
,
param
.
getBaseTime
(),
machines
,
orders
,
materials
,
machineScheduler
,
materialRequirementService
,
sceneId
);
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
)
{
if
(
opcount
<
800
)
{
FileHelper
.
writeLogFile
(
"模拟退火+爬山法优化-----------开始-------"
);
FileHelper
.
writeLogFile
(
"模拟退火+爬山法优化-----------开始-------"
);
Chromosome
saHcOptimized
=
_simulatedAnnealing
.
batchSearchGetMax
(
population
,
saDecoder1
,
machines
);
Chromosome
saHcOptimized
=
_simulatedAnnealing
.
searchWithHillClimbing
(
population
.
get
(
0
),
_vns
,
saDecoder1
,
machines
);
FileHelper
.
writeLogFile
(
"模拟退火+爬山法优化-----------结束-------"
);
FileHelper
.
writeLogFile
(
"模拟退火+爬山法优化-----------结束-------"
);
return
getBestChromosome
(
saHcOptimized
,
param
.
getBaseTime
(),
starttime
);
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
);
}
List
<
List
<
Chromosome
>>
combinedFronts
=
_nsgaIIUtils
.
parallelFastNonDominatedSort
(
population
);
Chromosome
best
=
ProductionDeepCopyUtil
.
deepCopy
(
population
.
get
(
0
),
Chromosome
.
class
);
// GetBest(combinedFronts,"初始");
int
ordercount
=
globalOpList
.
stream
()
int
ordercount
=
globalOpList
.
stream
()
.
mapToInt
(
GlobalOperationInfo:
:
getGroupId
)
.
mapToInt
(
GlobalOperationInfo:
:
getGroupId
)
.
max
()
.
max
()
.
orElse
(
0
);
.
orElse
(
0
);
Chromosome
best
=
GetBest
(
combinedFronts
,
"初始"
);
// best=fronts.get(0).stream()
// .max(Comparator.comparingDouble(Chromosome::getFitness))
// .orElse(null);
double
bestFitness
=
best
.
getFitness
();
if
(
population
.
size
()<
param
.
getTournamentSize
())
if
(
population
.
size
()<
param
.
getTournamentSize
())
{
{
...
@@ -185,7 +190,8 @@ int opcount=allOperations.size();
...
@@ -185,7 +190,8 @@ int opcount=allOperations.size();
}
}
int
Iteration
=
0
;
int
noImproveCount
=
0
;
int
maxNoImprove
=
10
;
// 步骤2:迭代进化
// 步骤2:迭代进化
FileHelper
.
writeLogFile
(
"迭代进化-----------开始-------"
+
param
.
getMaxIterations
());
FileHelper
.
writeLogFile
(
"迭代进化-----------开始-------"
+
param
.
getMaxIterations
());
for
(
int
iter
=
0
;
iter
<
param
.
getMaxIterations
();
iter
++)
{
for
(
int
iter
=
0
;
iter
<
param
.
getMaxIterations
();
iter
++)
{
...
@@ -193,6 +199,7 @@ int opcount=allOperations.size();
...
@@ -193,6 +199,7 @@ int opcount=allOperations.size();
FileHelper
.
writeLogFile
(
"迭代进化------"
+
iter
+
"-----开始-------"
);
FileHelper
.
writeLogFile
(
"迭代进化------"
+
iter
+
"-----开始-------"
);
// 计算种群适应度标准差,微调参数
// 计算种群适应度标准差,微调参数
double
fitnessStd
=
_fitnessCalculator
.
calculateFitnessStd
(
population
);
double
fitnessStd
=
_fitnessCalculator
.
calculateFitnessStd
(
population
);
param
.
fineTuneParams
(
iter
,
fitnessStd
);
param
.
fineTuneParams
(
iter
,
fitnessStd
);
...
@@ -204,141 +211,62 @@ int opcount=allOperations.size();
...
@@ -204,141 +211,62 @@ int opcount=allOperations.size();
}
}
FileHelper
.
writeLogFile
(
"选择操作-----------开始-------"
);
FileHelper
.
writeLogFile
(
"选择操作-----------开始-------"
);
// 选择前移除适应度为 0 或明显劣于当前最优解的个体,减少选择池规模:
double
minValidFitness
=
bestFitness
*
0.5
;
// 保留最优解50%以上的个体
List
<
Chromosome
>
validPopulation
=
population
.
stream
()
.
filter
(
c
->
c
.
getFitness
()
>=
minValidFitness
)
.
collect
(
Collectors
.
toList
());
// 选择操作
// 选择操作
List
<
Chromosome
>
selected
=
geneticOps
.
tournamentSelection
(
validP
opulation
);
List
<
Chromosome
>
selected
=
geneticOps
.
tournamentSelection
(
p
opulation
);
FileHelper
.
writeLogFile
(
"选择操作-----------结束-------"
);
FileHelper
.
writeLogFile
(
"选择操作-----------结束-------"
);
// 变邻域搜索
FileHelper
.
writeLogFile
(
"变邻域搜索-----------开始-------"
);
GeneticDecoder
vnsDecoder
=
new
GeneticDecoder
(
_GlobalParam
,
param
.
getBaseTime
(),
machines
,
orders
,
materials
,
machineScheduler
,
materialRequirementService
,
sceneId
);
List
<
Chromosome
>
vnsImproved
=
_vns
.
search
(
selected
,
vnsDecoder
,
param
);
selected
.
addAll
(
vnsImproved
);
FileHelper
.
writeLogFile
(
"变邻域搜索-----------结束-------"
);
// 模拟退火全局搜索
FileHelper
.
writeLogFile
(
"模拟退火搜索-----------开始-------"
);
GeneticDecoder
saDecoder
=
new
GeneticDecoder
(
_GlobalParam
,
param
.
getBaseTime
(),
machines
,
orders
,
materials
,
machineScheduler
,
materialRequirementService
,
sceneId
);
List
<
Chromosome
>
saImproved
=
new
ArrayList
<>();
for
(
Chromosome
chromosome
:
selected
)
{
// Chromosome saOptimized = _simulatedAnnealing.search(chromosome, saDecoder, param);
// saImproved.add(saOptimized);
}
selected
.
addAll
(
saImproved
);
FileHelper
.
writeLogFile
(
"模拟退火搜索-----------结束-------"
);
// 多种局部搜索算法并行
FileHelper
.
writeLogFile
(
"并行局部搜索-----------开始-------"
);
GeneticDecoder
parallelDecoder
=
new
GeneticDecoder
(
_GlobalParam
,
param
.
getBaseTime
(),
machines
,
orders
,
materials
,
machineScheduler
,
materialRequirementService
,
sceneId
);
List
<
Chromosome
>
parallelImproved
=
new
ArrayList
<>();
for
(
Chromosome
chromosome
:
selected
)
{
Chromosome
parallelOptimized
=
_parallelLocalSearch
.
search
(
chromosome
,
parallelDecoder
,
param
);
parallelImproved
.
add
(
parallelOptimized
);
}
selected
.
addAll
(
parallelImproved
);
FileHelper
.
writeLogFile
(
"并行局部搜索-----------结束-------"
);
// 禁忌搜索+模拟退火
FileHelper
.
writeLogFile
(
"禁忌搜索+模拟退火-----------开始-------"
);
GeneticDecoder
tsDecoder
=
new
GeneticDecoder
(
_GlobalParam
,
param
.
getBaseTime
(),
machines
,
orders
,
materials
,
machineScheduler
,
materialRequirementService
,
sceneId
);
List
<
Chromosome
>
tsImproved
=
new
ArrayList
<>();
for
(
Chromosome
chromosome
:
selected
)
{
Chromosome
tsOptimized
=
_tabuSearchWithSA
.
search
(
chromosome
,
tsDecoder
,
param
);
tsImproved
.
add
(
tsOptimized
);
}
selected
.
addAll
(
tsImproved
);
FileHelper
.
writeLogFile
(
"禁忌搜索+模拟退火-----------结束-------"
);
// 交叉操作
// 交叉操作
FileHelper
.
writeLogFile
(
"交叉操作-----------开始-------"
);
FileHelper
.
writeLogFile
(
"交叉操作-----------开始-------"
);
List
<
Chromosome
>
nextPopulation
=
new
ArrayList
<>();
List
<
Chromosome
>
newPopulation
=
new
ArrayList
<>();
for
(
int
i
=
0
;
i
<
selected
.
size
();
i
+=
2
)
{
newPopulation
.
add
(
best
);
if
(
i
+
1
>=
selected
.
size
())
{
int
n
=
0
;
selected
.
get
(
i
).
setID
(
UUID
.
randomUUID
().
toString
());
while
(
newPopulation
.
size
()
<
param
.
getPopulationSize
())
{
nextPopulation
.
add
(
selected
.
get
(
i
));
// 选择父代
break
;
FileHelper
.
writeLogFile
(
"交叉-----------开始-------"
+
n
);
}
Chromosome
parent1
=
selected
.
get
(
rnd
.
nextInt
(
selected
.
size
()));
Chromosome
parent1
=
selected
.
get
(
i
);
Chromosome
parent2
=
selected
.
get
(
rnd
.
nextInt
(
selected
.
size
()));
Chromosome
parent2
=
selected
.
get
(
i
+
1
);
// 交叉
if
(
rnd
.
nextDouble
()
<
param
.
getCrossoverProb
())
{
Chromosome
child
=
parent1
;
// 假设PoxCrossover返回包含两个子染色体的数组
// if (rnd.nextDouble() < param.getCrossoverProb()) {
Pair
<
Chromosome
,
Chromosome
>
children
=
geneticOps
.
poxCrossover
(
parent1
,
parent2
,
ordercount
);
// // 假设PoxCrossover返回包含两个子染色体的数组
nextPopulation
.
add
(
children
.
getFirst
());
// Pair<Chromosome, Chromosome> children = geneticOps.poxCrossover(parent1, parent2, ordercount);
nextPopulation
.
add
(
children
.
getSecond
());
// child=children.getFirst();
}
else
{
// initDataToChromosome(child,param, allOperations,globalOpList);
nextPopulation
.
add
(
parent1
);
// child.setID(UUID.randomUUID().toString());
nextPopulation
.
add
(
parent2
);
// }
}
// // 变异
}
// if (rnd.nextDouble() < param.getMutationProb()) {
FileHelper
.
writeLogFile
(
"交叉操作-----------结束-------"
);
// geneticOps.mutate(child, globalOpList);
FileHelper
.
writeLogFile
(
"变异操作-----------开始-------"
);
// }
// 变异操作
// 核心融合链(工业级标准顺序:GA生成子代 → SA跳坑 → VNS扩邻域 → TS精优化)
List
<
Chromosome
>
nextPopulation1
=
new
ArrayList
<>();
child
=
_simulatedAnnealing
.
search
(
child
,
_tabuSearch
,
_vns
,
saDecoder1
,
machines
);
for
(
Chromosome
chromosome
:
nextPopulation
)
{
child
=
_vns
.
search
(
child
,
vnsDecoder1
,
machines
);
if
(
rnd
.
nextDouble
()
<
param
.
getMutationProb
())
{
child
=
_tabuSearch
.
search
(
child
,
_vns
,
tabuDecoder1
,
machines
);
Chromosome
chromosome1
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
chromosome1
.
setID
(
UUID
.
randomUUID
().
toString
());
geneticOps
.
mutate
(
chromosome1
,
globalOpList
);
nextPopulation1
.
add
(
chromosome1
);
}
}
nextPopulation
.
addAll
(
nextPopulation1
);
FileHelper
.
writeLogFile
(
"变异操作-----------结束-------"
);
FileHelper
.
writeLogFile
(
"变异批量解码-----------开始-------"
);
Chromosomedecode
(
param
,
allOperations
,
globalOpList
,
nextPopulation
);
newPopulation
.
add
(
child
);
FileHelper
.
writeLogFile
(
"变异批量解码-----------结束-------"
);
// // 精英保留
// List<Chromosome> population1 = population.stream()
// .sorted((c1, c2) -> Double.compare(c2.getFitness(), c1.getFitness()))
// .collect(Collectors.toList()); // 降序排序
//
//
// List<Chromosome> elites = population1.subList(0, param.getElitismCount());
List
<
Chromosome
>
newPopulation
=
new
ArrayList
<>();
FileHelper
.
writeLogFile
(
"交叉-----------结束-------"
+
n
);
//保留一定数量的上一代
List
<
Chromosome
>
populationcopy
=
_nsgaIIUtils
.
selectNextPopulation
(
combinedFronts
,
param
.
getPopulationSize
()/
5
);
newPopulation
.
addAll
(
populationcopy
);
newPopulation
.
addAll
(
nextPopulation
);
newPopulation
=
chromosomeDistinct1
(
newPopulation
);
FileHelper
.
writeLogFile
(
"非支配排序-----------开始-------"
);
// 2.7 非支配排序
combinedFronts
=
_nsgaIIUtils
.
parallelFastNonDominatedSort
(
newPopulation
);
FileHelper
.
writeLogFile
(
"非支配排序-----------结束-------"
);
// 2.8 选择下一代种群
population
=
_nsgaIIUtils
.
selectNextPopulation
(
combinedFronts
,
param
.
getPopulationSize
());
// 更新种群
// population = newPopulation.stream()
// .limit(param.getPopulationSize() )
// .collect(Collectors.toList());
}
population
=
chromosomeDistinctByObjectives
(
newPopulation
);;
best
=
GetBest
(
combinedFronts
,
String
.
valueOf
(
iter
));
if
(
_fitnessCalculator
.
isBetter
(
population
.
get
(
0
),
best
))
if
(
bestFitness
<
best
.
getFitness
())
{
{
bestFitness
=
best
.
getFitness
();
best
=
ProductionDeepCopyUtil
.
deepCopy
(
population
.
get
(
0
),
Chromosome
.
class
);
// GetBest(combinedFronts,"初始");
Iteration
=
1
;
noImproveCount
=
1
;
}
else
{
}
else
{
Iteration
++;
noImproveCount
++;
if
(
Iteration
>
5
)
{
if
(
noImproveCount
>
5
)
{
// 当连续 5 代无最优解提升时,降低交叉概率(如从 0.8 降至 0.5)、提高变异概率(如从 0.1 升至 0.2)
// 当连续 5 代无最优解提升时,降低交叉概率(如从 0.8 降至 0.5)、提高变异概率(如从 0.1 升至 0.2)
param
.
fineTuneParams
();
param
.
fineTuneParams
();
}
}
}
}
if
(
Iteration
>
10
)
if
(
noImproveCount
>
maxNoImprove
)
{
{
break
;
break
;
}
}
...
@@ -379,18 +307,7 @@ int opcount=allOperations.size();
...
@@ -379,18 +307,7 @@ int opcount=allOperations.size();
return
best
;
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
)
private
List
<
Chromosome
>
chromosomeDistinct
(
List
<
Chromosome
>
population
)
{
{
if
(
population
==
null
)
if
(
population
==
null
)
...
@@ -413,7 +330,7 @@ int opcount=allOperations.size();
...
@@ -413,7 +330,7 @@ int opcount=allOperations.size();
}
}
/**
/**
* 按Objectives去重
,相同目标值的方案只保留一个(保留fitness最大的)
* 按Objectives去重
*/
*/
private
List
<
Chromosome
>
chromosomeDistinctByObjectives
(
List
<
Chromosome
>
population
)
private
List
<
Chromosome
>
chromosomeDistinctByObjectives
(
List
<
Chromosome
>
population
)
{
{
...
@@ -440,34 +357,36 @@ int opcount=allOperations.size();
...
@@ -440,34 +357,36 @@ int opcount=allOperations.size();
}
}
}
}
return
new
ArrayList
<>(
objectivesMap
.
values
());
// 按 fitnessLevel 倒序排序(多层次比较)
List
<
Chromosome
>
result
=
new
ArrayList
<>(
objectivesMap
.
values
());
result
.
sort
((
c1
,
c2
)
->
{
if
(
isBetter
(
c1
,
c2
))
{
return
-
1
;
// c1 比 c2 好,c1 应该排在前面
}
else
if
(
isBetter
(
c2
,
c1
))
{
return
1
;
// c2 比 c1 好,c2 应该排在前面
}
else
{
return
0
;
// 两者相等
}
}
});
private
List
<
Chromosome
>
chromosomeDistinct1
(
List
<
Chromosome
>
population
)
return
result
;
{
}
if
(
population
==
null
)
/**
{
* 比较两个染色体的优劣(基于fitnessLevel多层次比较)
FileHelper
.
writeLogFile
(
String
.
format
(
"排产-----------方案数量---%d-------"
,
0
));
*/
return
population
;
private
boolean
isBetter
(
Chromosome
c1
,
Chromosome
c2
)
{
for
(
int
i
=
0
;
i
<
c1
.
getFitnessLevel
().
length
;
i
++)
{
double
[]
Fitness1
=
c1
.
getFitnessLevel
();
double
[]
Fitness2
=
c2
.
getFitnessLevel
();
if
(
Fitness1
[
i
]
>
Fitness2
[
i
])
{
return
true
;
}
}
return
false
;
}
}
// 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
)
{
private
void
WriteKpis
(
List
<
List
<
Chromosome
>>
fronts
,
String
index
)
{
for
(
int
i
=
0
;
i
<
fronts
.
size
();
i
++)
for
(
int
i
=
0
;
i
<
fronts
.
size
();
i
++)
{
{
...
@@ -496,6 +415,40 @@ int opcount=allOperations.size();
...
@@ -496,6 +415,40 @@ int opcount=allOperations.size();
new
ThreadPoolExecutor
.
CallerRunsPolicy
()
// 任务满了主线程执行,不丢失任务
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
)
private
void
Chromosomedecode
(
ScheduleParams
param
,
List
<
Entry
>
allOperations
,
List
<
GlobalOperationInfo
>
globalOpList
,
List
<
Chromosome
>
population
)
{
{
FileHelper
.
writeLogFile
(
"解码---------------"
+
population
.
size
()
);
FileHelper
.
writeLogFile
(
"解码---------------"
+
population
.
size
()
);
...
@@ -542,7 +495,7 @@ int opcount=allOperations.size();
...
@@ -542,7 +495,7 @@ int opcount=allOperations.size();
// chromosome.setInitMachines(ProductionDeepCopyUtil.deepCopyList(machines,Machine.class)); // 简单拷贝,实际可能需要深拷贝
// chromosome.setInitMachines(ProductionDeepCopyUtil.deepCopyList(machines,Machine.class)); // 简单拷贝,实际可能需要深拷贝
// _sceneService.saveChromosomeToFile(chromosome, "12345679");
// _sceneService.saveChromosomeToFile(chromosome, "12345679");
decoder
.
decodeChromosomeWithCache
(
chromosome
);
decoder
.
decodeChromosomeWithCache
(
chromosome
,
false
);
// if (chromosome.getFitness() == 0) {
// if (chromosome.getFitness() == 0) {
// chromosome.setFitness(_fitnessCalculator.calculateFitness(chromosome, _objectiveWeights));
// chromosome.setFitness(_fitnessCalculator.calculateFitness(chromosome, _objectiveWeights));
// }
// }
...
...
src/main/java/com/aps/service/Algorithm/Initialization.java
View file @
f2a1529b
...
@@ -343,7 +343,7 @@ chromo.setOrders(new CopyOnWriteArrayList<>(orders));
...
@@ -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
<>();
List
<
Chromosome
>
population
=
new
ArrayList
<>();
int
populationSize
=
param
.
getPopulationSize
();
int
populationSize
=
param
.
getPopulationSize
();
this
.
baseTime
=
param
.
getBaseTime
();
this
.
baseTime
=
param
.
getBaseTime
();
...
...
src/main/java/com/aps/service/Algorithm/MaterialRequirementService.java
View file @
f2a1529b
...
@@ -179,7 +179,7 @@ public class MaterialRequirementService {
...
@@ -179,7 +179,7 @@ public class MaterialRequirementService {
double
allneeded
=
component
.
getSpentQty
().
doubleValue
()/
component
.
getMainQty
().
doubleValue
()
*
operation
.
getQuantity
();
double
allneeded
=
component
.
getSpentQty
().
doubleValue
()/
component
.
getMainQty
().
doubleValue
()
*
operation
.
getQuantity
();
OrderMaterialRequirement
orderMaterialRequirement
=
CreateMaterialRequirement
(
material
,
orderId
,
""
,
operation
,
OrderMaterialRequirement
orderMaterialRequirement
=
CreateMaterialRequirement
(
material
,
orderId
,
""
,
operation
,
allneeded
,
component
.
getSpentQty
().
doubleValue
(),
component
.
getMainQty
().
doubleValue
(),
operation
.
getQuantity
());
allneeded
,
component
.
getSpentQty
().
doubleValue
(),
component
.
getMainQty
().
doubleValue
(),
operation
.
getQuantity
()
,
baseTime
);
orderMaterialRequirement
.
setBomId
(
component
.
getStrId
());
orderMaterialRequirement
.
setBomId
(
component
.
getStrId
());
if
(!
material
.
getMaterialTypeName
().
equals
(
"MP"
)
&&
isIsCheckSf
)
{
if
(!
material
.
getMaterialTypeName
().
equals
(
"MP"
)
&&
isIsCheckSf
)
{
materialIds
.
add
(
materialId
);
//半成品ID
materialIds
.
add
(
materialId
);
//半成品ID
...
@@ -503,8 +503,6 @@ public class MaterialRequirementService {
...
@@ -503,8 +503,6 @@ public class MaterialRequirementService {
* @return 所有物料需求列表
* @return 所有物料需求列表
*/
*/
public
List
<
OrderMaterialRequirement
>
buildMultiLevelRequirementNetwork
(
Chromosome
chromosome
,
String
sceneId
,
LocalDateTime
_baseTime
,
GlobalParam
_globalParam
)
{
public
List
<
OrderMaterialRequirement
>
buildMultiLevelRequirementNetwork
(
Chromosome
chromosome
,
String
sceneId
,
LocalDateTime
_baseTime
,
GlobalParam
_globalParam
)
{
baseTime
=
_baseTime
;
globalParam
=
_globalParam
;
List
<
OrderMaterialRequirement
>
allRequirements
=
new
ArrayList
<>();
List
<
OrderMaterialRequirement
>
allRequirements
=
new
ArrayList
<>();
List
<
Order
>
childorders
=
new
ArrayList
<>();
List
<
Order
>
childorders
=
new
ArrayList
<>();
List
<
Entry
>
_newEntrys
=
new
ArrayList
<>();
List
<
Entry
>
_newEntrys
=
new
ArrayList
<>();
...
@@ -519,7 +517,7 @@ public class MaterialRequirementService {
...
@@ -519,7 +517,7 @@ public class MaterialRequirementService {
.
entrySet
().
stream
()
.
entrySet
().
stream
()
.
collect
(
Collectors
.
toMap
(
Map
.
Entry
::
getKey
,
e
->
0
));
.
collect
(
Collectors
.
toMap
(
Map
.
Entry
::
getKey
,
e
->
0
));
List
<
Integer
>
operationSequencing
=
chromosome
.
getOperationSequencing
(
);
List
<
Integer
>
operationSequencing
=
new
ArrayList
<>(
chromosome
.
getOperationSequencing
()
);
orders
.
forEach
(
t
->
clearFinishOrder
(
t
));
orders
.
forEach
(
t
->
clearFinishOrder
(
t
));
...
@@ -546,7 +544,7 @@ public class MaterialRequirementService {
...
@@ -546,7 +544,7 @@ public class MaterialRequirementService {
// 调用BuildOperationBOM方法(返回结果对象替代out参数)
// 调用BuildOperationBOM方法(返回结果对象替代out参数)
BOMBuildResult
operationResult
=
buildOperationSFBOM
(
operation
.
getOrderId
(),
""
,
BOMBuildResult
operationResult
=
buildOperationSFBOM
(
operation
.
getOrderId
(),
""
,
operation
.
getQuantity
(),
operation
,
1
,
demand
,
sceneId
,
chromosome
);
operation
.
getQuantity
(),
operation
,
1
,
demand
,
sceneId
,
chromosome
,
_baseTime
,
_globalParam
);
// // 合并物料需求和子订单
// // 合并物料需求和子订单
if
(
operationResult
!=
null
)
{
if
(
operationResult
!=
null
)
{
allRequirements
.
addAll
(
operationResult
.
getMaterialRequirements
());
allRequirements
.
addAll
(
operationResult
.
getMaterialRequirements
());
...
@@ -567,13 +565,13 @@ public class MaterialRequirementService {
...
@@ -567,13 +565,13 @@ public class MaterialRequirementService {
return
allRequirements
;
return
allRequirements
;
}
}
private
void
clearFinishOrder
(
Order
order
)
private
void
clearFinishOrder
(
Order
order
)
{
{
if
(
order
.
getFinishOrderId
()
==
null
)
{
if
(
order
.
getFinishOrderId
()
==
null
)
{
order
.
setFinishOrderId
(
new
ArrayList
<>());
order
.
setFinishOrderId
(
new
ArrayList
<>());
order
.
setTargetFinishedOperationId
(
new
ArrayList
<>());
order
.
setTargetFinishedOperationId
(
new
ArrayList
<>());
}
}
}
}
/**
/**
* 构建订单BOM
* 构建订单BOM
...
@@ -586,7 +584,7 @@ private void clearFinishOrder (Order order)
...
@@ -586,7 +584,7 @@ private void clearFinishOrder (Order order)
* @return 包含物料需求列表和子订单列表的结果对象
* @return 包含物料需求列表和子订单列表的结果对象
*/
*/
public
BOMBuildResult
buildOrderBOM
(
String
sceneId
,
int
parent
,
String
materialID
,
String
mainorderId
,
public
BOMBuildResult
buildOrderBOM
(
String
sceneId
,
int
parent
,
String
materialID
,
String
mainorderId
,
String
childorderId
,
double
parentQuantity
,
int
level
,
Order
forder
,
int
finishOpertionID
,
Chromosome
chromosome
)
{
String
childorderId
,
double
parentQuantity
,
int
level
,
Order
forder
,
int
finishOpertionID
,
Chromosome
chromosome
,
LocalDateTime
baseTime
,
GlobalParam
globalParam
)
{
forder
.
setCreateBom
(
true
);
forder
.
setCreateBom
(
true
);
List
<
RoutingHeader
>
headers
=
GetRoutingHeader
(
sceneId
);
List
<
RoutingHeader
>
headers
=
GetRoutingHeader
(
sceneId
);
...
@@ -627,7 +625,7 @@ private void clearFinishOrder (Order order)
...
@@ -627,7 +625,7 @@ private void clearFinishOrder (Order order)
}
}
// 调用BuildOperationBOM方法(返回结果对象替代out参数)
// 调用BuildOperationBOM方法(返回结果对象替代out参数)
BOMBuildResult
operationResult
=
buildOperationBOM
(
mainorderId
,
childorderId
,
BOMBuildResult
operationResult
=
buildOperationBOM
(
mainorderId
,
childorderId
,
parentQuantity
,
operation
,
level
,
forder
,
sceneId
,
chromosome
);
parentQuantity
,
operation
,
level
,
forder
,
sceneId
,
chromosome
,
baseTime
,
globalParam
);
// // 合并物料需求和子订单
// // 合并物料需求和子订单
if
(
operationResult
!=
null
)
{
if
(
operationResult
!=
null
)
{
materialRequirements
.
addAll
(
operationResult
.
getMaterialRequirements
());
materialRequirements
.
addAll
(
operationResult
.
getMaterialRequirements
());
...
@@ -650,7 +648,7 @@ private void clearFinishOrder (Order order)
...
@@ -650,7 +648,7 @@ private void clearFinishOrder (Order order)
* @return 包含物料需求列表和子订单列表的结果对象(替代C#的out参数)
* @return 包含物料需求列表和子订单列表的结果对象(替代C#的out参数)
*/
*/
public
BOMBuildResult
buildOperationBOM
(
String
orderId
,
String
childorderId
,
double
parentQuantity
,
public
BOMBuildResult
buildOperationBOM
(
String
orderId
,
String
childorderId
,
double
parentQuantity
,
Entry
operation
,
int
level
,
Order
forder
,
String
sceneId
,
Chromosome
chromosome
)
{
Entry
operation
,
int
level
,
Order
forder
,
String
sceneId
,
Chromosome
chromosome
,
LocalDateTime
baseTime
,
GlobalParam
globalParam
)
{
List
<
OrderMaterialRequirement
>
materialRequirements
=
new
ArrayList
<>();
List
<
OrderMaterialRequirement
>
materialRequirements
=
new
ArrayList
<>();
List
<
Order
>
_childorders
=
new
ArrayList
<>();
List
<
Order
>
_childorders
=
new
ArrayList
<>();
List
<
Entry
>
_newEntrys
=
new
ArrayList
<>();
List
<
Entry
>
_newEntrys
=
new
ArrayList
<>();
...
@@ -678,7 +676,7 @@ private void clearFinishOrder (Order order)
...
@@ -678,7 +676,7 @@ private void clearFinishOrder (Order order)
return
null
;
return
null
;
}
}
OrderMaterialRequirement
orderMaterial
=
CreateMaterialRequirement
(
material
,
orderId
,
childorderId
,
operation
,
allneeded
,
component
.
getSpentQty
().
doubleValue
(),
component
.
getMainQty
().
doubleValue
()
,
parentQuantity
);
OrderMaterialRequirement
orderMaterial
=
CreateMaterialRequirement
(
material
,
orderId
,
childorderId
,
operation
,
allneeded
,
component
.
getSpentQty
().
doubleValue
(),
component
.
getMainQty
().
doubleValue
()
,
parentQuantity
,
baseTime
);
orderMaterial
.
setLevel
(
level
);
orderMaterial
.
setLevel
(
level
);
orderMaterial
.
setBomId
(
component
.
getStrId
());
orderMaterial
.
setBomId
(
component
.
getStrId
());
materialRequirements
.
add
(
orderMaterial
);
materialRequirements
.
add
(
orderMaterial
);
...
@@ -713,7 +711,7 @@ private void clearFinishOrder (Order order)
...
@@ -713,7 +711,7 @@ private void clearFinishOrder (Order order)
BOMBuildResult
childResult
=
buildOrderBOM
(
sceneId
,
0
,
orderMaterial
.
getMaterialId
(),
BOMBuildResult
childResult
=
buildOrderBOM
(
sceneId
,
0
,
orderMaterial
.
getMaterialId
(),
orderId
,
order
.
getOrderId
(),
orderId
,
order
.
getOrderId
(),
order
.
getQuantity
(),
l
,
order
,
operation
.
getId
(),
chromosome
);
order
.
getQuantity
(),
l
,
order
,
operation
.
getId
(),
chromosome
,
baseTime
,
globalParam
);
// materialRequirements.addAll(childResult.getMaterialRequirements());
// materialRequirements.addAll(childResult.getMaterialRequirements());
_childorders
.
addAll
(
childResult
.
getChildOrders
());
_childorders
.
addAll
(
childResult
.
getChildOrders
());
_newEntrys
.
addAll
(
childResult
.
getNewEntrys
());
_newEntrys
.
addAll
(
childResult
.
getNewEntrys
());
...
@@ -743,7 +741,7 @@ private void clearFinishOrder (Order order)
...
@@ -743,7 +741,7 @@ private void clearFinishOrder (Order order)
childorder
.
setQuantity
((
int
)
orderMaterial
.
getQjQty
());
childorder
.
setQuantity
((
int
)
orderMaterial
.
getQjQty
());
childorder
.
setFinishOrderId
(
new
ArrayList
<>());
childorder
.
setFinishOrderId
(
new
ArrayList
<>());
childorder
.
getFinishOrderId
().
add
(
forder
.
getId
());
childorder
.
getFinishOrderId
().
add
(
forder
.
getId
());
childorder
.
setNewCreate
(
true
);
childorder
.
setNew
Sf
Create
(
true
);
childorder
.
setTargetFinishedOperationId
(
new
ArrayList
<>());
childorder
.
setTargetFinishedOperationId
(
new
ArrayList
<>());
childorder
.
getTargetFinishedOperationId
().
add
(
operation
.
getId
());
childorder
.
getTargetFinishedOperationId
().
add
(
operation
.
getId
());
childorder
.
setSerie
(
forder
.
getSerie
());
childorder
.
setSerie
(
forder
.
getSerie
());
...
@@ -769,7 +767,7 @@ private void clearFinishOrder (Order order)
...
@@ -769,7 +767,7 @@ private void clearFinishOrder (Order order)
int
l
=
level
+
1
;
int
l
=
level
+
1
;
BOMBuildResult
childResult
=
buildOrderBOM
(
sceneId
,
0
,
orderMaterial
.
getMaterialId
(),
BOMBuildResult
childResult
=
buildOrderBOM
(
sceneId
,
0
,
orderMaterial
.
getMaterialId
(),
orderId
,
childorder
.
getOrderId
(),
orderId
,
childorder
.
getOrderId
(),
childorder
.
getQuantity
(),
l
,
childorder
,
0
,
chromosome
);
childorder
.
getQuantity
(),
l
,
childorder
,
0
,
chromosome
,
baseTime
,
globalParam
);
// materialRequirements.addAll(childResult.getMaterialRequirements());
// materialRequirements.addAll(childResult.getMaterialRequirements());
_childorders
.
addAll
(
childResult
.
getChildOrders
());
_childorders
.
addAll
(
childResult
.
getChildOrders
());
_newEntrys
.
addAll
(
childResult
.
getNewEntrys
());
_newEntrys
.
addAll
(
childResult
.
getNewEntrys
());
...
@@ -792,10 +790,10 @@ private void clearFinishOrder (Order order)
...
@@ -792,10 +790,10 @@ private void clearFinishOrder (Order order)
RoutingHeader
headers1
=
headers
.
stream
()
RoutingHeader
headers1
=
headers
.
stream
()
.
filter
(
t
->
t
.
getMaterialId
().
equals
(
materialID
))
.
filter
(
t
->
t
.
getMaterialId
().
equals
(
materialID
))
.
findFirst
().
orElse
(
null
);
.
findFirst
().
orElse
(
null
);
if
(
headers1
==
null
)
if
(
headers1
==
null
)
{
{
return
null
;
return
null
;
}
}
routingIds
=
headers1
.
getId
().
longValue
();
routingIds
=
headers1
.
getId
().
longValue
();
...
@@ -921,7 +919,7 @@ if(headers1==null)
...
@@ -921,7 +919,7 @@ if(headers1==null)
* @return 包含物料需求列表和子订单列表的结果对象(替代C#的out参数)
* @return 包含物料需求列表和子订单列表的结果对象(替代C#的out参数)
*/
*/
public
BOMBuildResult
buildOperationSFBOM
(
String
orderId
,
String
childorderId
,
double
parentQuantity
,
public
BOMBuildResult
buildOperationSFBOM
(
String
orderId
,
String
childorderId
,
double
parentQuantity
,
Entry
operation
,
int
level
,
Order
forder
,
String
sceneId
,
Chromosome
chromosome
)
{
Entry
operation
,
int
level
,
Order
forder
,
String
sceneId
,
Chromosome
chromosome
,
LocalDateTime
baseTime
,
GlobalParam
globalParam
)
{
List
<
OrderMaterialRequirement
>
materialRequirements
=
new
ArrayList
<>();
List
<
OrderMaterialRequirement
>
materialRequirements
=
new
ArrayList
<>();
List
<
Order
>
_childorders
=
new
ArrayList
<>();
List
<
Order
>
_childorders
=
new
ArrayList
<>();
List
<
Entry
>
_newEntrys
=
new
ArrayList
<>();
List
<
Entry
>
_newEntrys
=
new
ArrayList
<>();
...
@@ -980,7 +978,7 @@ if(headers1==null)
...
@@ -980,7 +978,7 @@ if(headers1==null)
BOMBuildResult
childResult
=
buildOrderBOM
(
sceneId
,
0
,
orderMaterial
.
getMaterialId
(),
BOMBuildResult
childResult
=
buildOrderBOM
(
sceneId
,
0
,
orderMaterial
.
getMaterialId
(),
orderId
,
order
.
getOrderId
(),
orderId
,
order
.
getOrderId
(),
order
.
getQuantity
(),
l
,
order
,
operation
.
getId
(),
chromosome
);
order
.
getQuantity
(),
l
,
order
,
operation
.
getId
(),
chromosome
,
baseTime
,
globalParam
);
materialRequirements
.
addAll
(
childResult
.
getMaterialRequirements
());
materialRequirements
.
addAll
(
childResult
.
getMaterialRequirements
());
_childorders
.
addAll
(
childResult
.
getChildOrders
());
_childorders
.
addAll
(
childResult
.
getChildOrders
());
_newEntrys
.
addAll
(
childResult
.
getNewEntrys
());
_newEntrys
.
addAll
(
childResult
.
getNewEntrys
());
...
@@ -1010,7 +1008,7 @@ if(headers1==null)
...
@@ -1010,7 +1008,7 @@ if(headers1==null)
childorder
.
setQuantity
((
int
)
orderMaterial
.
getQjQty
());
childorder
.
setQuantity
((
int
)
orderMaterial
.
getQjQty
());
childorder
.
setFinishOrderId
(
new
ArrayList
<>());
childorder
.
setFinishOrderId
(
new
ArrayList
<>());
childorder
.
getFinishOrderId
().
add
(
forder
.
getId
());
childorder
.
getFinishOrderId
().
add
(
forder
.
getId
());
childorder
.
setNew
Create
(
true
);
childorder
.
setNewSf
Create
(
true
);
childorder
.
setTargetFinishedOperationId
(
new
ArrayList
<>());
childorder
.
setTargetFinishedOperationId
(
new
ArrayList
<>());
childorder
.
getTargetFinishedOperationId
().
add
(
operation
.
getId
());
childorder
.
getTargetFinishedOperationId
().
add
(
operation
.
getId
());
childorder
.
setSerie
(
forder
.
getSerie
());
childorder
.
setSerie
(
forder
.
getSerie
());
...
@@ -1036,7 +1034,7 @@ if(headers1==null)
...
@@ -1036,7 +1034,7 @@ if(headers1==null)
int
l
=
level
+
1
;
int
l
=
level
+
1
;
BOMBuildResult
childResult
=
buildOrderBOM
(
sceneId
,
0
,
orderMaterial
.
getMaterialId
(),
BOMBuildResult
childResult
=
buildOrderBOM
(
sceneId
,
0
,
orderMaterial
.
getMaterialId
(),
orderId
,
childorder
.
getOrderId
(),
orderId
,
childorder
.
getOrderId
(),
childorder
.
getQuantity
(),
l
,
childorder
,
0
,
chromosome
);
childorder
.
getQuantity
(),
l
,
childorder
,
0
,
chromosome
,
baseTime
,
globalParam
);
materialRequirements
.
addAll
(
childResult
.
getMaterialRequirements
());
materialRequirements
.
addAll
(
childResult
.
getMaterialRequirements
());
_childorders
.
addAll
(
childResult
.
getChildOrders
());
_childorders
.
addAll
(
childResult
.
getChildOrders
());
_newEntrys
.
addAll
(
childResult
.
getNewEntrys
());
_newEntrys
.
addAll
(
childResult
.
getNewEntrys
());
...
@@ -1089,7 +1087,7 @@ if(headers1==null)
...
@@ -1089,7 +1087,7 @@ if(headers1==null)
}
}
private
OrderMaterialRequirement
CreateMaterialRequirement
(
Material
material
,
String
orderId
,
String
childorderId
,
Entry
operation
,
double
need
,
double
spentQty
,
double
mainQty
,
double
qty
)
{
private
OrderMaterialRequirement
CreateMaterialRequirement
(
Material
material
,
String
orderId
,
String
childorderId
,
Entry
operation
,
double
need
,
double
spentQty
,
double
mainQty
,
double
qty
,
LocalDateTime
baseTime
)
{
OrderMaterialRequirement
orderMaterial
=
new
OrderMaterialRequirement
();
OrderMaterialRequirement
orderMaterial
=
new
OrderMaterialRequirement
();
orderMaterial
.
setOrderId
(
orderId
);
orderMaterial
.
setOrderId
(
orderId
);
...
@@ -1140,7 +1138,7 @@ if(headers1==null)
...
@@ -1140,7 +1138,7 @@ if(headers1==null)
* @return 包含物料需求列表和子订单列表的结果对象(替代C#的out参数)
* @return 包含物料需求列表和子订单列表的结果对象(替代C#的out参数)
*/
*/
public
void
EditOperationBOM
(
Entry
operation
,
Chromosome
chromosome
,
LocalDateTime
earliestStartTime
,
GeneticDecoder
coder
,
Map
<
Long
,
CopyOnWriteArrayList
<
GAScheduleResult
>>
machineTasksCache
)
{
public
void
EditOperationBOM
(
Entry
operation
,
Chromosome
chromosome
,
LocalDateTime
earliestStartTime
,
GeneticDecoder
coder
,
Map
<
Long
,
CopyOnWriteArrayList
<
GAScheduleResult
>>
machineTasksCache
,
Map
<
Integer
,
Entry
>
entryIndexById
,
Map
<
Integer
,
GAScheduleResult
>
scheduleIndexById
,
LocalDateTime
baseTime
)
{
List
<
OrderMaterialRequirement
>
materialRequirements
=
new
ArrayList
<>();
List
<
OrderMaterialRequirement
>
materialRequirements
=
new
ArrayList
<>();
String
sceneId
=
chromosome
.
getScenarioID
();
String
sceneId
=
chromosome
.
getScenarioID
();
...
@@ -1247,7 +1245,7 @@ if(headers1==null)
...
@@ -1247,7 +1245,7 @@ if(headers1==null)
continue
;
continue
;
}
}
MaterialInTransit
(
material
,
""
,
orderMaterial
,
needed
,
earliestStartTime
);
MaterialInTransit
(
material
,
""
,
orderMaterial
,
needed
,
earliestStartTime
,
materials
);
needed
-=
orderMaterial
.
getUseTransit
();
needed
-=
orderMaterial
.
getUseTransit
();
...
@@ -1268,7 +1266,7 @@ if(headers1==null)
...
@@ -1268,7 +1266,7 @@ if(headers1==null)
break
;
break
;
}
}
MaterialInTransit
(
material1
,
rsr
.
getMaterialid
(),
orderMaterial1
,
needed
,
earliestStartTime
);
MaterialInTransit
(
material1
,
rsr
.
getMaterialid
(),
orderMaterial1
,
needed
,
earliestStartTime
,
materials
);
needed
-=
orderMaterial1
.
getUseTransit
();
needed
-=
orderMaterial1
.
getUseTransit
();
...
@@ -1319,7 +1317,7 @@ if(headers1==null)
...
@@ -1319,7 +1317,7 @@ if(headers1==null)
for
(
Integer
orderid
:
orderids
)
{
for
(
Integer
orderid
:
orderids
)
{
coder
.
ClearorderOperationResult
(
chromosome
,
orderid
);
coder
.
ClearorderOperationResult
(
chromosome
,
orderid
);
coder
.
EditorderOperation
(
chromosome
,
orderid
,
needed
,
machineTasksCache
);
coder
.
EditorderOperation
(
chromosome
,
orderid
,
needed
,
machineTasksCache
,
entryIndexById
,
scheduleIndexById
);
}
}
}
else
{
}
else
{
...
@@ -1376,14 +1374,14 @@ if(headers1==null)
...
@@ -1376,14 +1374,14 @@ if(headers1==null)
private
void
MaterialInTransit
(
Material
material
,
String
materialId
,
OrderMaterialRequirement
orderMaterial
,
double
needed
,
LocalDateTime
earliestStartTime
){
private
void
MaterialInTransit
(
Material
material
,
String
materialId
,
OrderMaterialRequirement
orderMaterial
,
double
needed
,
LocalDateTime
earliestStartTime
,
List
<
Material
>
materials
){
// 处理在途物料
// 处理在途物料
double
accumulated
=
0
;
double
accumulated
=
0
;
LocalDateTime
earliestTime
=
LocalDateTime
.
of
(
2000
,
1
,
1
,
0
,
0
,
0
);
LocalDateTime
earliestTime
=
LocalDateTime
.
of
(
2000
,
1
,
1
,
0
,
0
,
0
);
double
useTransit
=
0
;
double
useTransit
=
0
;
if
(
material
==
null
)
{
if
(
material
==
null
)
{
material
=
_
materials
.
stream
()
material
=
materials
.
stream
()
.
filter
(
m
->
m
.
getId
().
equals
(
materialId
))
.
filter
(
m
->
m
.
getId
().
equals
(
materialId
))
.
findFirst
()
.
findFirst
()
.
orElse
(
null
);
.
orElse
(
null
);
...
...
src/main/java/com/aps/service/Algorithm/MaterialRequirementServicebf.java
View file @
f2a1529b
...
@@ -894,7 +894,7 @@ public class MaterialRequirementServicebf {
...
@@ -894,7 +894,7 @@ public class MaterialRequirementServicebf {
childorder
.
setQuantity
((
int
)
orderMaterial
.
getQjQty
());
childorder
.
setQuantity
((
int
)
orderMaterial
.
getQjQty
());
childorder
.
setFinishOrderId
(
new
ArrayList
<>());
childorder
.
setFinishOrderId
(
new
ArrayList
<>());
childorder
.
getFinishOrderId
().
add
(
forder
.
getId
());
childorder
.
getFinishOrderId
().
add
(
forder
.
getId
());
childorder
.
setNewCreate
(
true
);
childorder
.
setNew
Sf
Create
(
true
);
childorder
.
setTargetFinishedOperationId
(
new
ArrayList
<>());
childorder
.
setTargetFinishedOperationId
(
new
ArrayList
<>());
childorder
.
getTargetFinishedOperationId
().
add
(
operation
.
getId
());
childorder
.
getTargetFinishedOperationId
().
add
(
operation
.
getId
());
childorder
.
setSerie
(
forder
.
getSerie
());
childorder
.
setSerie
(
forder
.
getSerie
());
...
...
src/main/java/com/aps/service/Algorithm/ParallelLocalSearch.java
deleted
100644 → 0
View file @
bb00017a
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.ArrayList
;
import
java.util.List
;
import
java.util.concurrent.*
;
/**
* 多种局部搜索算法并行
*/
public
class
ParallelLocalSearch
{
private
final
ExecutorService
executor
;
private
GlobalParam
globalParam
;
private
List
<
Entry
>
allOperations
;
private
List
<
GlobalOperationInfo
>
globalOpList
;
private
FitnessCalculator
fitnessCalculator
;
private
ObjectiveWeights
objectiveWeights
;
public
ParallelLocalSearch
(
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
.
executor
=
Executors
.
newFixedThreadPool
(
Runtime
.
getRuntime
().
availableProcessors
());
}
/**
* 并行局部搜索
*/
public
Chromosome
search
(
Chromosome
chromosome
,
GeneticDecoder
decoder
,
ScheduleParams
param
)
{
List
<
Callable
<
Chromosome
>>
tasks
=
new
ArrayList
<>();
// 添加爬山法任务
// tasks.add(() -> {
// HillClimbing hillClimbing = new HillClimbing(globalParam, allOperations, globalOpList, fitnessCalculator, objectiveWeights);
// return hillClimbing.search(chromosome, decoder, param);
// });
// 添加变邻域搜索任务
tasks
.
add
(()
->
{
VariableNeighborhoodSearch
vns
=
new
VariableNeighborhoodSearch
(
globalParam
,
allOperations
,
globalOpList
,
fitnessCalculator
,
objectiveWeights
);
return
vns
.
search
(
chromosome
,
decoder
,
param
);
});
// 添加模拟退火任务
// tasks.add(() -> {
// SimulatedAnnealing sa = new SimulatedAnnealing(globalParam, allOperations, globalOpList, fitnessCalculator, objectiveWeights);
// return sa.search(chromosome, decoder, param);
// });
// 执行所有任务
List
<
Chromosome
>
results
=
new
ArrayList
<>();
try
{
List
<
Future
<
Chromosome
>>
futures
=
executor
.
invokeAll
(
tasks
);
for
(
Future
<
Chromosome
>
future
:
futures
)
{
results
.
add
(
future
.
get
());
}
}
catch
(
InterruptedException
|
ExecutionException
e
)
{
e
.
printStackTrace
();
}
// 选择最优解
Chromosome
best
=
chromosome
;
for
(
Chromosome
result
:
results
)
{
if
(
isBetter
(
result
,
best
))
{
best
=
result
;
}
}
return
best
;
}
/**
* 比较两个染色体的优劣
*/
private
boolean
isBetter
(
Chromosome
c1
,
Chromosome
c2
)
{
return
c1
.
getFitness
()
>
c2
.
getFitness
();
}
/**
* 关闭线程池
*/
public
void
shutdown
()
{
executor
.
shutdown
();
}
}
\ No newline at end of file
src/main/java/com/aps/service/Algorithm/ScheduleOperationService.java
View file @
f2a1529b
...
@@ -1885,7 +1885,7 @@ if(targetOp.getSequence()>1) {
...
@@ -1885,7 +1885,7 @@ if(targetOp.getSequence()>1) {
decoder
.
decode
(
chromosome
);
decoder
.
decode
(
chromosome
,
false
);
KpiCalculator
kpiCalculator
=
new
KpiCalculator
(
chromosome
);
KpiCalculator
kpiCalculator
=
new
KpiCalculator
(
chromosome
);
kpiCalculator
.
calculatekpi
();
kpiCalculator
.
calculatekpi
();
...
...
src/main/java/com/aps/service/Algorithm/SimulatedAnnealing.java
View file @
f2a1529b
package
com
.
aps
.
service
.
Algorithm
;
package
com
.
aps
.
service
.
Algorithm
;
import
com.aps.common.util.FileHelper
;
import
com.aps.common.util.FileHelper
;
import
com.aps.common.util.GlobalCacheUtil
;
import
com.aps.common.util.ProductionDeepCopyUtil
;
import
com.aps.common.util.ProductionDeepCopyUtil
;
import
com.aps.entity.Algorithm.*
;
import
com.aps.entity.Algorithm.*
;
import
com.aps.entity.basic.Entry
;
import
com.aps.entity.Algorithm.IDAndChildID.GroupResult
;
import
com.aps.entity.basic.GlobalParam
;
import
com.aps.entity.basic.*
;
import
com.aps.entity.basic.Machine
;
import
com.aps.entity.basic.MachineOption
;
import
java.util.*
;
import
java.util.*
;
import
java.util.concurrent.*
;
import
java.util.concurrent.*
;
...
@@ -18,17 +17,39 @@ import java.util.stream.Collectors;
...
@@ -18,17 +17,39 @@ import java.util.stream.Collectors;
public
class
SimulatedAnnealing
{
public
class
SimulatedAnnealing
{
private
final
Random
rnd
=
new
Random
();
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
<
Entry
>
allOperations
;
private
Map
<
String
,
Entry
>
entrys
;
private
List
<
Order
>
orders
;
private
List
<
Material
>
materials
;
private
List
<
GroupResult
>
_entryRel
;
private
FitnessCalculator
fitnessCalculator
;
private
Map
<
String
,
Entry
>
entrys
;
private
Map
<
Integer
,
Entry
>
entrybyids
;
private
Map
<
Integer
,
Entry
>
entrybyids
;
public
SimulatedAnnealing
(
List
<
Entry
>
allOperations
)
{
public
SimulatedAnnealing
(
List
<
Entry
>
allOperations
,
List
<
Order
>
orders
,
List
<
Material
>
materials
,
List
<
GroupResult
>
entryRel
,
FitnessCalculator
_fitnessCalculator
)
{
this
.
allOperations
=
allOperations
;
this
.
allOperations
=
allOperations
;
this
.
orders
=
orders
;
this
.
materials
=
materials
;
Map
<
Integer
,
Object
>
mp
=
buildEntryKey
()
;
_entryRel
=
entryRel
;
Map
<
Integer
,
Object
>
mp
=
buildEntryKey
();
this
.
fitnessCalculator
=
_fitnessCalculator
;
entrys
=(
Map
<
String
,
Entry
>)
mp
.
get
(
1
);
entrys
=(
Map
<
String
,
Entry
>)
mp
.
get
(
1
);
entrybyids
=(
Map
<
Integer
,
Entry
>)
mp
.
get
(
2
);
entrybyids
=(
Map
<
Integer
,
Entry
>)
mp
.
get
(
2
);
...
@@ -40,7 +61,7 @@ private Map<String, Entry> entrys;
...
@@ -40,7 +61,7 @@ private Map<String, Entry> entrys;
new
ArrayBlockingQueue
<>(
200
),
// 有界队列,避免内存溢出
new
ArrayBlockingQueue
<>(
200
),
// 有界队列,避免内存溢出
new
ThreadPoolExecutor
.
CallerRunsPolicy
()
// 任务满了主线程执行,不丢失任务
new
ThreadPoolExecutor
.
CallerRunsPolicy
()
// 任务满了主线程执行,不丢失任务
);
);
public
List
<
Chromosome
>
batchSearch
(
List
<
Chromosome
>
chromosomes
,
GeneticDecoder
decoder
,
List
<
Machine
>
machines
)
{
public
List
<
Chromosome
>
batchSearch
(
List
<
Chromosome
>
chromosomes
,
VariableNeighborhoodSearch
vns
,
GeneticDecoder
decoder
,
List
<
Machine
>
machines
)
{
List
<
Chromosome
>
saHcOptimized
=
new
ArrayList
<>();
List
<
Chromosome
>
saHcOptimized
=
new
ArrayList
<>();
// CompletableFuture.allOf(chromosomes.stream()
// CompletableFuture.allOf(chromosomes.stream()
// .map(chromosome -> CompletableFuture.runAsync(() -> {
// .map(chromosome -> CompletableFuture.runAsync(() -> {
...
@@ -50,15 +71,15 @@ private Map<String, Entry> entrys;
...
@@ -50,15 +71,15 @@ private Map<String, Entry> entrys;
// .toArray(CompletableFuture[]::new))
// .toArray(CompletableFuture[]::new))
// .join();
// .join();
for
(
Chromosome
chromosome:
chromosomes
)
{
for
(
Chromosome
chromosome:
chromosomes
)
{
Chromosome
optimized
=
searchWithHillClimbing
(
chromosome
,
decoder
,
machines
);
Chromosome
optimized
=
searchWithHillClimbing
(
chromosome
,
vns
,
decoder
,
machines
);
saHcOptimized
.
add
(
optimized
);
saHcOptimized
.
add
(
optimized
);
}
}
return
saHcOptimized
;
return
saHcOptimized
;
}
}
public
Chromosome
batchSearchGetMax
(
List
<
Chromosome
>
chromosomes
,
GeneticDecoder
decoder
,
List
<
Machine
>
machines
)
{
public
Chromosome
batchSearchGetMax
(
List
<
Chromosome
>
chromosomes
,
VariableNeighborhoodSearch
vns
,
GeneticDecoder
decoder
,
List
<
Machine
>
machines
)
{
List
<
Chromosome
>
saHcOptimized
=
batchSearch
(
chromosomes
,
decoder
,
machines
);
List
<
Chromosome
>
saHcOptimized
=
batchSearch
(
chromosomes
,
vns
,
decoder
,
machines
);
int
bestidx
=
Getbest
(
saHcOptimized
,
null
);
int
bestidx
=
Getbest
(
saHcOptimized
,
null
);
if
(
bestidx
>-
1
)
{
if
(
bestidx
>-
1
)
{
...
@@ -72,17 +93,18 @@ private Map<String, Entry> entrys;
...
@@ -72,17 +93,18 @@ private Map<String, Entry> entrys;
* 模拟退火搜索,当温度降低到一定程度后切换到爬山法
* 模拟退火搜索,当温度降低到一定程度后切换到爬山法
* 流程:模拟退火全局探索(按概率接受劣解)→ 降温 → 温度低时爬山法局部求精 → 输出最优
* 流程:模拟退火全局探索(按概率接受劣解)→ 降温 → 温度低时爬山法局部求精 → 输出最优
*/
*/
public
Chromosome
searchWithHillClimbing
(
Chromosome
chromosome
,
GeneticDecoder
decoder
,
List
<
Machine
>
machines
)
{
public
Chromosome
searchWithHillClimbing
(
Chromosome
chromosome
,
VariableNeighborhoodSearch
vns
,
GeneticDecoder
decoder
,
List
<
Machine
>
machines
)
{
FileHelper
.
writeLogFile
(
"模拟退火+爬山法 - 开始执行"
);
log
(
"模拟退火+爬山法 - 开始执行"
,
true
);
Chromosome
current
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
Chromosome
current
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
Chromosome
best
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
Chromosome
best
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
writeKpi
(
best
);
writeKpi
(
best
);
// 初始化解码
// 记录初始KPI用于计算改进率
double
[]
initialFitnessLevel
=
best
.
getFitnessLevel
().
clone
();
double
initialFitness
=
best
.
getFitness
();
// FileHelper.writeLogFile
("模拟退火+爬山法 - 初始化解码完成");
// log
("模拟退火+爬山法 - 初始化解码完成");
// 初始化温度
// 初始化温度
double
temperature
=
100.0
;
double
temperature
=
100.0
;
...
@@ -90,19 +112,26 @@ private Map<String, Entry> entrys;
...
@@ -90,19 +112,26 @@ private Map<String, Entry> entrys;
double
temperatureThreshold
=
1.0
;
double
temperatureThreshold
=
1.0
;
int
maxIterations
=
300
;
int
maxIterations
=
300
;
int
noImproveCount
=
0
;
int
noImproveCount
=
0
;
int
maxNoImprove
=
50
;
int
maxNoImprove
=
30
;
// 降低最大无改进次数
// 新增:改进率监控参数
int
stagnantWindow
=
15
;
// 观察窗口大小
int
[]
recentImprovements
=
new
int
[
stagnantWindow
];
// 记录最近窗口内的改进情况
double
improvementRateThreshold
=
0.05
;
// 改进率阈值(5%)
FileHelper
.
writeLogFile
(
String
.
format
(
"模拟退火+爬山法 - 参数配置:温度=%.1f, 降温率=%.2f, 阈值=%.1f, 最大迭代
=%d"
,
log
(
String
.
format
(
"模拟退火+爬山法 - 参数配置:温度=%.1f, 降温率=%.2f, 阈值=%.1f, 最大迭代=%d, 最大无改进
=%d"
,
temperature
,
coolingRate
,
temperatureThreshold
,
maxIterations
));
temperature
,
coolingRate
,
temperatureThreshold
,
maxIterations
,
maxNoImprove
));
int
acceptCount
=
0
;
int
acceptCount
=
0
;
int
improveCount
=
0
;
int
improveCount
=
0
;
int
totalIterations
=
0
;
for
(
int
i
=
0
;
i
<
maxIterations
;
i
++)
{
for
(
int
i
=
0
;
i
<
maxIterations
;
i
++)
{
totalIterations
=
i
+
1
;
boolean
improved
=
false
;
boolean
improved
=
false
;
// 1. 使用智能策略生成邻域解(找瓶颈工序/设备)
// 1. 使用智能策略生成邻域解(找瓶颈工序/设备)
Chromosome
neighbor
=
generateNeighbor
(
current
);
Chromosome
neighbor
=
vns
.
generateNeighbor
(
current
);
// 2. 解码
// 2. 解码
decode
(
decoder
,
neighbor
,
machines
);
decode
(
decoder
,
neighbor
,
machines
);
...
@@ -124,7 +153,10 @@ private Map<String, Entry> entrys;
...
@@ -124,7 +153,10 @@ private Map<String, Entry> entrys;
improved
=
true
;
improved
=
true
;
improveCount
++;
improveCount
++;
noImproveCount
=
0
;
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
);
}
}
}
}
...
@@ -132,713 +164,330 @@ private Map<String, Entry> entrys;
...
@@ -132,713 +164,330 @@ private Map<String, Entry> entrys;
noImproveCount
++;
noImproveCount
++;
}
}
// 5. 降温
// 记录本次改进情况
temperature
*=
coolingRate
;
if
(
totalIterations
<=
stagnantWindow
)
{
recentImprovements
[
totalIterations
-
1
]
=
improved
?
1
:
0
;
// 每50次迭代输出一次状态
if
((
i
+
1
)
%
50
==
0
)
{
FileHelper
.
writeLogFile
(
String
.
format
(
"模拟退火+爬山法 - 迭代%d/%d:温度=%.4f, 接受数=%d, 改进数=%d, 无改进连续=%d"
,
i
+
1
,
maxIterations
,
temperature
,
acceptCount
,
improveCount
,
noImproveCount
));
}
}
// 6. 提前停止条件:温度低于阈值 或 连续多次没改进
// 5. 降温
if
(
temperature
<
temperatureThreshold
||
noImproveCount
>=
maxNoImprove
)
{
temperature
*=
coolingRate
;
String
stopReason
=
temperature
<
temperatureThreshold
?
"温度低于阈值"
:
"连续无改进达到上限"
;
FileHelper
.
writeLogFile
(
String
.
format
(
"模拟退火+爬山法 - 提前停止:%s,迭代%d次,最终温度=%.4f"
,
stopReason
,
i
+
1
,
temperature
));
FileHelper
.
writeLogFile
(
"模拟退火+爬山法 - 切换到爬山法求精"
);
HillClimbing
hillClimbing
=
new
HillClimbing
(
allOperations
);
Chromosome
refined
=
hillClimbing
.
search
(
best
,
decoder
,
machines
);
FileHelper
.
writeLogFile
(
"模拟退火+爬山法 - 爬山法求精完成"
);
return
refined
;
// 每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
));
}
}
FileHelper
.
writeLogFile
(
String
.
format
(
"模拟退火+爬山法 - 完成所有%d次迭代,最终fitness=%.4f"
,
// 6. 提前停止条件
maxIterations
,
best
.
getFitness
()));
boolean
shouldStop
=
false
;
String
stopReason
=
""
;
// 7. 输出全局最优排产
if
(
temperature
<
temperatureThreshold
)
{
return
best
;
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
);
}
}
private
void
writeKpi
(
Chromosome
chromosome
)
{
String
fitness
=
""
;
double
[]
fitness1
=
chromosome
.
getFitnessLevel
();
for
(
int
i
=
0
;
i
<
fitness1
.
length
;
i
++)
{
fitness
+=
fitness1
[
i
]
+
","
;
}
}
FileHelper
.
writeLogFile
(
String
.
format
(
"爬山法 - kpi:%s"
,
fitness
));
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
);
* 计算能量差(基于fitnessLevel数组的比较)
log
(
"模拟退火+爬山法 - 爬山法求精完成"
);
*/
private
double
calculateEnergyDifference
(
Chromosome
neighbor
,
Chromosome
current
)
{
double
[]
neighborFitness
=
neighbor
.
getFitnessLevel
();
double
[]
currentFitness
=
current
.
getFitnessLevel
();
// 计算加权能量差
return
refined
;
double
diff
=
0
;
for
(
int
i
=
0
;
i
<
neighborFitness
.
length
;
i
++)
{
diff
+=
(
neighborFitness
[
i
]
-
currentFitness
[
i
]);
}
}
return
diff
;
}
}
/**
log
(
String
.
format
(
"模拟退火+爬山法 - 完成所有%d次迭代,最终fitness=%.4f"
,
* 按优先级分组工序
maxIterations
,
best
.
getFitness
()),
true
);
*/
logFinalSummary
(
best
,
initialFitnessLevel
,
initialFitness
,
improveCount
,
totalIterations
);
private
Map
<
Double
,
List
<
Entry
>>
groupOperationsByPriority
()
{
Map
<
Double
,
List
<
Entry
>>
groups
=
new
HashMap
<>();
for
(
Entry
op
:
allOperations
)
{
double
priority
=
op
.
getPriority
();
groups
.
computeIfAbsent
(
priority
,
k
->
new
ArrayList
<>()).
add
(
op
);
}
// 过滤掉:设备只有一个且只有一个GroupId的优先级组
Map
<
Double
,
List
<
Entry
>>
filteredGroups
=
new
HashMap
<>();
for
(
Map
.
Entry
<
Double
,
List
<
Entry
>>
entry
:
groups
.
entrySet
())
{
List
<
Entry
>
ops
=
entry
.
getValue
();
// 检查是否所有工序都只有一个设备选项
boolean
allSingleMachine
=
ops
.
stream
()
.
allMatch
(
op
->
op
.
getMachineOptions
().
size
()
<=
1
);
// 检查是否只有一个GroupId
// 7. 输出全局最优排产
Set
<
Integer
>
groupIds
=
ops
.
stream
()
return
best
;
.
map
(
Entry:
:
getGroupId
)
.
collect
(
Collectors
.
toSet
());
// 如果两个条件都满足,过滤掉这个优先级组
if
(!(
allSingleMachine
&&
groupIds
.
size
()
<=
1
))
{
filteredGroups
.
put
(
entry
.
getKey
(),
ops
);
}
}
}
return
filteredGroups
;
}
/**
/**
* 构建位置索引:groupId_sequence -> position
* 模拟退火搜索
* 流程:模拟退火全局探索(按概率接受劣解)→ 降温 → 输出最优
*/
*/
private
Map
<
String
,
Integer
>
buildPositionIndex
(
Chromosome
chromosome
)
{
public
Chromosome
search
(
Chromosome
chromosome
,
TabuSearch
tabusearch
,
VariableNeighborhoodSearch
vns
,
GeneticDecoder
decoder
,
List
<
Machine
>
machines
)
{
Map
<
String
,
Integer
>
index
=
new
HashMap
<>();
log
(
"模拟退火 - 开始执行"
,
true
);
List
<
Integer
>
os
=
chromosome
.
getOperationSequencing
();
Map
<
Integer
,
Integer
>
orderProcessCounter
=
new
HashMap
<>();
for
(
int
i
=
0
;
i
<
os
.
size
();
i
++)
{
int
groupId
=
os
.
get
(
i
);
int
count
=
orderProcessCounter
.
getOrDefault
(
groupId
,
0
)
+
1
;
orderProcessCounter
.
put
(
groupId
,
count
);
String
key
=
groupId
+
"_"
+
count
;
index
.
put
(
key
,
i
);
}
return
index
;
}
/**
Chromosome
current
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
* 构建位置索引:groupId_sequence -> Machines position
decode
(
decoder
,
current
,
machines
);
*/
Chromosome
best
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
private
Map
<
String
,
Integer
>
buildEntryMachinePositionIndex
(
Chromosome
chromosome
)
{
writeKpi
(
best
);
Map
<
String
,
Integer
>
index
=
new
HashMap
<>();
// 初始化解码
List
<
GlobalOperationInfo
>
globalOpList
=
chromosome
.
getGlobalOpList
();
for
(
int
i
=
0
;
i
<
globalOpList
.
size
();
i
++)
{
// 记录初始KPI用于计算改进率
GlobalOperationInfo
globalOp
=
globalOpList
.
get
(
i
);
double
[]
initialFitnessLevel
=
best
.
getFitnessLevel
().
clone
();
Entry
op
=
globalOp
.
getOp
();
double
initialFitness
=
best
.
getFitness
();
int
groupId
=
op
.
getGroupId
();
int
count
=
op
.
getSequence
();
String
key
=
groupId
+
"_"
+
count
;
// log("模拟退火+爬山法 - 初始化解码完成");
index
.
put
(
key
,
i
);
}
return
index
;
}
/**
// 初始化温度
* 构建位置->Entry索引
double
temperature
=
100.0
;
*/
double
coolingRate
=
0.95
;
private
Map
<
Integer
,
Entry
>
buildPositionToEntryIndex
(
Chromosome
chromosome
,
Map
<
String
,
Entry
>
entrys
)
{
double
temperatureThreshold
=
1.0
;
Map
<
Integer
,
Entry
>
index
=
new
HashMap
<>()
;
int
maxIterations
=
300
;
List
<
Integer
>
os
=
chromosome
.
getOperationSequencing
()
;
int
noImproveCount
=
0
;
Map
<
Integer
,
Integer
>
orderProcessCounter
=
new
HashMap
<>();
int
maxNoImprove
=
20
;
// 降低最大无改进次数,更快提前结束
for
(
int
i
=
0
;
i
<
os
.
size
();
i
++)
{
// 新增:改进率监控参数
int
groupId
=
os
.
get
(
i
);
int
stagnantWindow
=
10
;
// 观察窗口大小
int
count
=
orderProcessCounter
.
getOrDefault
(
groupId
,
0
)
+
1
;
int
[]
recentImprovements
=
new
int
[
stagnantWindow
];
// 记录最近窗口内的改进情况
orderProcessCounter
.
put
(
groupId
,
count
);
double
improvementRateThreshold
=
0.001
;
// 改进率阈值
String
key
=
groupId
+
"_"
+
count
;
log
(
String
.
format
(
"模拟退火 - 参数配置:温度=%.1f, 降温率=%.2f, 阈值=%.1f, 最大迭代=%d, 最大无改进=%d"
,
Entry
op
=
entrys
.
get
(
key
);
temperature
,
coolingRate
,
temperatureThreshold
,
maxIterations
,
maxNoImprove
)
);
if
(
op
!=
null
)
{
int
acceptCount
=
0
;
index
.
put
(
i
,
op
);
int
improveCount
=
0
;
}
int
totalIterations
=
0
;
}
return
index
;
}
/**
* 构建Entry索引:op.getGroupId() + "_" + op.getSequence() -> Entry
*/
private
Map
<
Integer
,
Object
>
buildEntryKey
()
{
Map
<
Integer
,
Object
>
index0
=
new
HashMap
<>();
Map
<
String
,
Entry
>
index
=
new
HashMap
<>();
Map
<
Integer
,
Entry
>
index2
=
new
HashMap
<>();
List
<
Entry
>
allOps
=
this
.
allOperations
;
for
(
Entry
op
:
allOps
)
{
for
(
int
i
=
0
;
i
<
maxIterations
;
i
++)
{
String
key
=
op
.
getGroupId
()
+
"_"
+
op
.
getSequence
();
totalIterations
=
i
+
1
;
boolean
improved
=
false
;
log
(
String
.
format
(
"模拟退火 - 迭代%d:"
,
totalIterations
));
index
.
put
(
key
,
op
);
// 1. 使用智能策略生成邻域解(找瓶颈工序/设备)
index2
.
put
(
op
.
getId
(),
op
);
Chromosome
neighbor
=
vns
.
generateNeighbor
(
current
);
}
// 2. 解码
index0
.
put
(
1
,
index
);
decode
(
decoder
,
neighbor
,
machines
);
index0
.
put
(
2
,
index2
);
// 跳过禁忌解(除非是最优解)
return
index0
;
if
(
tabusearch
.
isTabu
(
neighbor
.
getGeneStr
())
&&
!
isBetter
(
current
,
best
))
{
temperature
*=
coolingRate
;
noImproveCount
++;
// 记录本次无改进
if
(
totalIterations
<=
stagnantWindow
)
{
recentImprovements
[
totalIterations
-
1
]
=
0
;
}
}
continue
;
/**
* 生成邻域解 - 智能策略:优先处理瓶颈工序/设备
* 策略:
* 1. 优先处理瓶颈设备上的工序(换设备)
* 2. 瓶颈设备上的工序往前移动
* 3. 非瓶颈设备上的工序往后移动(给瓶颈工序腾位置)
*/
private
Chromosome
generateNeighbor
(
Chromosome
chromosome
)
{
List
<
GAScheduleResult
>
results
=
chromosome
.
getResult
();
if
(
results
==
null
||
results
.
isEmpty
())
{
return
generateRandomNeighbor
(
chromosome
,
entrys
);
}
}
// 构建位置索引
// 3. 计算能量差
Map
<
String
,
Integer
>
positionIndex
=
buildPositionIndex
(
chromosome
);
double
energyDifference
=
calculateEnergyDifference
(
neighbor
,
current
);
Map
<
Integer
,
Entry
>
positionToEntryIndex
=
buildPositionToEntryIndex
(
chromosome
,
entrys
);
Map
<
String
,
Integer
>
MachinePositionIndex
=
buildEntryMachinePositionIndex
(
chromosome
);
// 1. 找出瓶颈设备
Long
bottleneckMachineId
=
findBottleneckMachine
(
chromosome
);
if
(
bottleneckMachineId
!=
null
)
{
// 4. 按概率接受新解(模拟退火核心:有概率接受劣解)
// 找出瓶颈设备上的工序
boolean
accepted
=
false
;
List
<
GAScheduleResult
>
bottleneckOps
=
findOpsOnBottleneckMachine
(
chromosome
,
bottleneckMachineId
);
if
(
energyDifference
>
0
||
rnd
.
nextDouble
()
<
Math
.
exp
(
energyDifference
/
temperature
))
{
current
=
neighbor
;
if
(!
bottleneckOps
.
isEmpty
())
{
acceptCount
++;
// 70%概率优先处理瓶颈设备
if
(
isBetter
(
current
,
best
))
{
if
(
rnd
.
nextDouble
()
<
0.7
)
{
best
=
ProductionDeepCopyUtil
.
deepCopy
(
current
,
Chromosome
.
class
);
int
strategy
=
rnd
.
nextInt
(
10
);
tabusearch
.
addToTabuList
(
best
.
getGeneStr
());
writeKpi
(
best
);
improved
=
true
;
improveCount
++;
noImproveCount
=
0
;
if
(
strategy
<=
3
)
// 记录改进详情
{
logImprovementDetails
(
best
,
initialFitnessLevel
,
initialFitness
,
totalIterations
);
// 策略1:瓶颈设备上的工序换设备
log
(
String
.
format
(
"模拟退火 - 迭代%d:找到更优解,fitness=%.4f"
,
totalIterations
,
best
.
getFitness
()));
return
tryChangeMachineForBottleneckOp
(
chromosome
,
bottleneckOps
,
entrys
,
MachinePositionIndex
);
}
else
if
(
strategy
<=
8
)
{
// 策略2:瓶颈设备上的工序往前移动
return
tryMoveBottleneckOpForward
(
chromosome
,
bottleneckOps
,
positionIndex
,
positionToEntryIndex
,
entrys
);
}
else
if
(
strategy
<=
10
)
{
// 策略3:非瓶颈设备上的工序往后移动
return
tryMoveNonBottleneckOpBackward
(
chromosome
,
bottleneckMachineId
,
positionIndex
,
positionToEntryIndex
,
entrys
);
}
}
}
}
}
}
// 默认策略:随机邻域
if
(!
improved
)
{
return
generateRandomNeighbor
(
chromosome
,
entrys
);
noImproveCount
++;
}
/**
* 识别瓶颈设备(利用率最高的设备)
*/
private
Long
findBottleneckMachine
(
Chromosome
chromosome
)
{
Map
<
Long
,
Double
>
utilization
=
calculateMachineUtilization
(
chromosome
);
if
(
utilization
.
isEmpty
())
{
return
null
;
}
}
return
utilization
.
entrySet
().
stream
()
// 记录本次改进情况
.
max
(
Map
.
Entry
.
comparingByValue
())
if
(
totalIterations
<=
stagnantWindow
)
{
.
map
(
Map
.
Entry
::
getKey
)
recentImprovements
[
totalIterations
-
1
]
=
improved
?
1
:
0
;
.
orElse
(
null
);
}
}
/**
// 5. 降温
* 查找在瓶颈设备上的工序
temperature
*=
coolingRate
;
*/
private
List
<
GAScheduleResult
>
findOpsOnBottleneckMachine
(
Chromosome
chromosome
,
Long
bottleneckMachineId
)
{
if
(
bottleneckMachineId
==
null
)
{
return
new
ArrayList
<>();
}
return
chromosome
.
getResult
().
stream
()
// 每次迭代都输出状态
.
filter
(
r
->
r
.
getMachineId
()
==
bottleneckMachineId
)
log
(
String
.
format
(
"模拟退火 - 迭代%d/%d:温度=%.4f, 接受数=%d, 改进数=%d, 无改进连续=%d, 总改进率=%.2f%%"
,
.
collect
(
Collectors
.
toList
());
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
;
}
}
/**
* 计算设备利用率
*/
private
Map
<
Long
,
Double
>
calculateMachineUtilization
(
Chromosome
chromosome
)
{
Map
<
Long
,
Double
>
utilization
=
new
HashMap
<>();
List
<
GAScheduleResult
>
results
=
chromosome
.
getResult
();
if
(
results
==
null
||
results
.
isEmpty
())
{
return
utilization
;
}
}
int
maxEndTime
=
results
.
stream
()
log
(
String
.
format
(
"模拟退火 - 完成所有%d次迭代,最终fitness=%.4f"
,
.
mapToInt
(
GAScheduleResult:
:
getEndTime
)
maxIterations
,
best
.
getFitness
()),
true
);
.
max
()
logFinalSummary
(
best
,
initialFitnessLevel
,
initialFitness
,
improveCount
,
totalIterations
);
.
orElse
(
1
);
Map
<
Long
,
List
<
GAScheduleResult
>>
machineResults
=
results
.
stream
()
// 7. 输出全局最优排产
.
collect
(
Collectors
.
groupingBy
(
GAScheduleResult:
:
getMachineId
));
return
best
;
for
(
Map
.
Entry
<
Long
,
List
<
GAScheduleResult
>>
entry
:
machineResults
.
entrySet
())
{
long
machineId
=
entry
.
getKey
();
List
<
GAScheduleResult
>
machineOps
=
entry
.
getValue
();
int
totalProcessingTime
=
machineOps
.
stream
()
.
mapToInt
(
r
->
r
.
getEndTime
()
-
r
.
getStartTime
())
.
sum
();
double
util
=
(
double
)
totalProcessingTime
/
maxEndTime
;
utilization
.
put
(
machineId
,
util
);
}
}
return
utilization
;
}
/**
/**
*
尝试给瓶颈设备上的工序换设备
*
记录改进详情
*/
*/
private
Chromosome
tryChangeMachineForBottleneckOp
(
Chromosome
chromosome
,
List
<
GAScheduleResult
>
bottleneckOps
,
Map
<
String
,
Entry
>
entrys
,
Map
<
String
,
Integer
>
MachinePositionIndex
)
{
private
void
logImprovementDetails
(
Chromosome
best
,
double
[]
initialFitnessLevel
,
double
initialFitness
,
int
iteration
)
{
// 优先选择有多设备选项的工序
StringBuilder
sb
=
new
StringBuilder
(
"模拟退火 - 改进详情: 迭代"
+
iteration
+
", "
);
List
<
GAScheduleResult
>
candidates
=
bottleneckOps
.
stream
()
double
[]
currentFitness
=
best
.
getFitnessLevel
();
.
filter
(
op
->
{
Entry
entry
=
entrybyids
.
get
(
op
.
getOperationId
());
return
entry
!=
null
&&
entry
.
getMachineOptions
().
size
()
>
1
;
})
.
collect
(
Collectors
.
toList
());
if
(
candidates
.
isEmpty
())
{
return
generateRandomNeighbor
(
chromosome
,
entrys
);
}
// 从候选中随机选择一个工序,给它换设备
GAScheduleResult
selectedOp
=
candidates
.
get
(
rnd
.
nextInt
(
candidates
.
size
()));
// 找到这个工序在globalOpList中的位置
for
(
int
i
=
0
;
i
<
currentFitness
.
length
;
i
++)
{
int
maPos
=
-
1
;
double
improvement
=
currentFitness
[
i
]
-
initialFitnessLevel
[
i
];
sb
.
append
(
String
.
format
(
"KPI%d: %.4f→%.4f(+%.4f) "
,
i
+
1
,
initialFitnessLevel
[
i
],
currentFitness
[
i
],
improvement
));
Entry
entry
=
entrybyids
.
get
(
selectedOp
.
getOperationId
());
if
(
entry
!=
null
&&
entry
.
getMachineOptions
().
size
()
>
1
)
{
maPos
=
MachinePositionIndex
.
get
(
entry
.
getGroupId
()
+
"_"
+
entry
.
getSequence
());
if
(
maPos
>=
0
)
{
return
generateMachineChangeForSpecificOp
(
chromosome
,
entry
.
getMachineOptions
(),
maPos
);
}
}
// 直接换设备
return
generateMachineChangeNeighbor
(
chromosome
);
}
/**
* 给指定位置的工序换设备
*/
private
Chromosome
generateMachineChangeForSpecificOp
(
Chromosome
chromosome
,
List
<
MachineOption
>
machineOptions
,
int
idx
)
{
Chromosome
neighbor
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
List
<
Integer
>
ms
=
neighbor
.
getMachineSelection
();
if
(!
ms
.
isEmpty
()
&&
idx
>=
0
&&
idx
<
ms
.
size
())
{
if
(
machineOptions
.
size
()
>
1
)
{
int
currentMachineSeq
=
ms
.
get
(
idx
);
List
<
Integer
>
availableMachines
=
new
ArrayList
<>();
for
(
int
i
=
1
;
i
<=
machineOptions
.
size
();
i
++)
{
if
(
i
!=
currentMachineSeq
)
{
availableMachines
.
add
(
i
);
}
}
}
if
(!
availableMachines
.
isEmpty
())
{
double
totalImprovement
=
best
.
getFitness
()
-
initialFitness
;
int
newMachineSeq
=
availableMachines
.
get
(
rnd
.
nextInt
(
availableMachines
.
size
()));
sb
.
append
(
String
.
format
(
"总Fitness: %.4f→%.4f(+%.4f)"
,
initialFitness
,
best
.
getFitness
(),
totalImprovement
));
ms
.
set
(
idx
,
newMachineSeq
);
log
(
sb
.
toString
());
neighbor
.
setMachineSelection
(
ms
);
}
}
}
return
neighbor
;
}
}
/**
/**
*
尝试将瓶颈设备上的工序往前移动
*
计算最近改进率
*/
*/
private
Chromosome
tryMoveBottleneckOpForward
(
Chromosome
chromosome
,
List
<
GAScheduleResult
>
bottleneckOps
,
private
double
calculateRecentImprovementRate
(
int
[]
recentImprovements
,
int
windowSize
)
{
Map
<
String
,
Integer
>
positionIndex
,
int
improveCount
=
0
;
Map
<
Integer
,
Entry
>
positionToEntryIndex
,
for
(
int
i
=
0
;
i
<
windowSize
;
i
++)
{
Map
<
String
,
Entry
>
entrys
)
{
improveCount
+=
recentImprovements
[
i
];
if
(
bottleneckOps
.
isEmpty
())
{
return
generateSwapNeighbor
(
chromosome
,
entrys
);
}
// 随机选择一个瓶颈工序
// 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
);
// 按优先级和订单完成时间排序:优先选择高优先级+延期订单的工序
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
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
;
});
GAScheduleResult
selectedOp
=
sortedBottleneckOps
.
get
(
rnd
.
nextInt
(
Math
.
min
(
5
,
sortedBottleneckOps
.
size
())));
Entry
entry
=
entrybyids
.
get
(
selectedOp
.
getOperationId
())
;
String
key
=
entry
.
getGroupId
()
+
"_"
+
entry
.
getSequence
();
Integer
opPos
=
positionIndex
.
get
(
key
);
if
(
opPos
==
null
||
opPos
<=
0
)
{
return
generateSwapNeighbor
(
chromosome
,
entrys
);
}
// 往前移动1-3步
// int steps = rnd.nextInt(3) + 1;
// return moveOperationForward(chromosome,positionToEntryIndex, opPos, steps);
// 使用插入方式往前移动(1-5步)
int
steps
=
rnd
.
nextInt
(
5
)
+
1
;
return
insertOperationForward
(
chromosome
,
opPos
,
steps
,
entrys
);
}
/**
* 计算每个订单的最后完成时间
*/
private
Map
<
Integer
,
Integer
>
calculateOrderCompletionTimes
(
List
<
GAScheduleResult
>
allResults
)
{
Map
<
Integer
,
Integer
>
orderEndTimes
=
new
HashMap
<>();
for
(
GAScheduleResult
result
:
allResults
)
{
int
groupId
=
result
.
getGroupId
();
int
endTime
=
result
.
getEndTime
();
orderEndTimes
.
put
(
groupId
,
Math
.
max
(
orderEndTimes
.
getOrDefault
(
groupId
,
0
),
endTime
));
}
return
orderEndTimes
;
}
/**
* 尝试将非瓶颈设备上的工序往后移动(给瓶颈工序腾位置)
*/
private
Chromosome
tryMoveNonBottleneckOpBackward
(
Chromosome
chromosome
,
Long
bottleneckMachineId
,
Map
<
String
,
Integer
>
positionIndex
,
Map
<
Integer
,
Entry
>
positionToEntryIndex
,
Map
<
String
,
Entry
>
entrys
)
{
List
<
GAScheduleResult
>
results
=
chromosome
.
getResult
();
if
(
results
==
null
)
{
return
generateSwapNeighbor
(
chromosome
,
entrys
);
}
// 找出非瓶颈设备上的工序
List
<
GAScheduleResult
>
nonBottleneckOps
=
results
.
stream
()
.
filter
(
r
->
r
.
getMachineId
()
!=
bottleneckMachineId
)
.
collect
(
Collectors
.
toList
());
if
(
nonBottleneckOps
.
isEmpty
())
{
return
generateSwapNeighbor
(
chromosome
,
entrys
);
}
}
return
(
double
)
improveCount
/
windowSize
;
// 随机选择一个非瓶颈工序
GAScheduleResult
randomOp
=
nonBottleneckOps
.
get
(
rnd
.
nextInt
(
nonBottleneckOps
.
size
()));
Entry
entry
=
entrybyids
.
get
(
randomOp
.
getOperationId
());
String
key
=
entry
.
getGroupId
()+
"_"
+
entry
.
getSequence
();
Integer
opPos
=
positionIndex
.
get
(
key
);
if
(
opPos
==
null
||
opPos
>=
chromosome
.
getOperationSequencing
().
size
()
-
1
)
{
return
generateSwapNeighbor
(
chromosome
,
entrys
);
}
}
// 往后移动1-3步
int
steps
=
rnd
.
nextInt
(
3
)
+
1
;
return
moveOperationBackward
(
chromosome
,
positionToEntryIndex
,
opPos
,
steps
);
}
/**
/**
*
将工序往前移动
*
记录最终总结
*/
*/
private
Chromosome
moveOperationForward
(
Chromosome
chromosome
,
Map
<
Integer
,
Entry
>
originalPositionIndex
,
int
pos
,
int
step
s
)
{
private
void
logFinalSummary
(
Chromosome
best
,
double
[]
initialFitnessLevel
,
double
initialFitness
,
int
improveCount
,
int
totalIteration
s
)
{
Chromosome
neighbor
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
StringBuilder
sb
=
new
StringBuilder
(
"模拟退火 - 最终总结: "
);
List
<
Integer
>
os
=
neighbor
.
getOperationSequencing
();
double
[]
currentFitness
=
best
.
getFitnessLevel
();
if
(
pos
<=
0
||
pos
>=
os
.
size
())
{
sb
.
append
(
String
.
format
(
"总迭代%d次, 成功改进%d次, 改进率%.2f%%. "
,
return
neighbor
;
totalIterations
,
improveCount
,
totalIterations
>
0
?
(
double
)
improveCount
/
totalIterations
*
100
:
0
));
}
// 获取要移动的工序和目标位置的工序(基于原始chromosome)
for
(
int
i
=
0
;
i
<
currentFitness
.
length
;
i
++)
{
Entry
opToMove
=
originalPositionIndex
.
get
(
pos
)
;
double
improvement
=
currentFitness
[
i
]
-
initialFitnessLevel
[
i
]
;
if
(
opToMove
==
null
)
{
sb
.
append
(
String
.
format
(
"KPI%d: %.4f→%.4f(%.2f%%) "
,
i
+
1
,
initialFitnessLevel
[
i
],
currentFitness
[
i
],
return
neighbor
;
initialFitnessLevel
[
i
]
>
0
?
improvement
/
initialFitnessLevel
[
i
]
*
100
:
0
))
;
}
}
int
targetPos
=
Math
.
max
(
0
,
pos
-
steps
);
double
totalImprovement
=
best
.
getFitness
()
-
initialFitness
;
Entry
targetOp
=
originalPositionIndex
.
get
(
targetPos
);
sb
.
append
(
String
.
format
(
"总Fitness: %.4f→%.4f(%.2f%%)"
,
initialFitness
,
best
.
getFitness
(),
initialFitness
>
0
?
totalImprovement
/
initialFitness
*
100
:
0
));
// 检查是否可以交换
log
(
sb
.
toString
());
if
(
targetOp
!=
null
&&
opToMove
.
getGroupId
()
==
targetOp
.
getGroupId
())
{
return
neighbor
;
}
if
(
targetOp
!=
null
&&
Math
.
abs
(
targetOp
.
getPriority
()
-
opToMove
.
getPriority
())
>
0.001
)
{
return
neighbor
;
}
}
// 直接交换到目标位置
java
.
util
.
Collections
.
swap
(
os
,
pos
,
targetPos
);
neighbor
.
setOperationSequencing
(
os
);
return
neighbor
;
}
/**
private
void
writeKpi
(
Chromosome
chromosome
)
{
* 将工序往后移动
String
fitness
=
""
;
*/
double
[]
fitness1
=
chromosome
.
getFitnessLevel
();
private
Chromosome
moveOperationBackward
(
Chromosome
chromosome
,
Map
<
Integer
,
Entry
>
originalPositionIndex
,
int
pos
,
int
steps
)
{
for
(
int
i
=
0
;
i
<
fitness1
.
length
;
i
++)
{
Chromosome
neighbor
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
List
<
Integer
>
os
=
neighbor
.
getOperationSequencing
();
if
(
pos
<
0
||
pos
>=
os
.
size
()
-
1
)
{
return
neighbor
;
}
// 获取要移动的工序和目标位置的工序(基于原始chromosome)
Entry
opToMove
=
originalPositionIndex
.
get
(
pos
);
fitness
+=
fitness1
[
i
]
+
","
;
if
(
opToMove
==
null
)
{
return
neighbor
;
}
}
int
targetPos
=
Math
.
min
(
os
.
size
()
-
1
,
pos
+
steps
);
log
(
String
.
format
(
"模拟退火 - kpi:%s"
,
fitness
),
true
);
Entry
targetOp
=
originalPositionIndex
.
get
(
targetPos
);
// 检查是否可以交换
if
(
targetOp
!=
null
&&
opToMove
.
getGroupId
()
==
targetOp
.
getGroupId
())
{
return
neighbor
;
}
if
(
targetOp
!=
null
&&
Math
.
abs
(
targetOp
.
getPriority
()
-
opToMove
.
getPriority
())
>
0.001
)
{
return
neighbor
;
}
// 直接交换到目标位置
java
.
util
.
Collections
.
swap
(
os
,
pos
,
targetPos
);
neighbor
.
setOperationSequencing
(
os
);
return
neighbor
;
}
}
/**
/**
*
将工序往前插入(不交换,直接插入到目标位置
)
*
计算能量差(基于fitnessLevel数组的比较
)
*/
*/
private
Chromosome
insertOperationForward
(
Chromosome
chromosome
,
int
pos
,
int
steps
,
Map
<
String
,
Entry
>
entrys
)
{
private
double
calculateEnergyDifference
(
Chromosome
neighbor
,
Chromosome
current
)
{
Chromosome
neighbor
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
double
[]
neighborFitness
=
neighbor
.
getFitnessLevel
();
List
<
Integer
>
os
=
neighbor
.
getOperationSequencing
();
double
[]
currentFitness
=
current
.
getFitnessLevel
();
if
(
pos
<=
0
||
pos
>=
os
.
size
())
{
return
neighbor
;
}
// 获取要移动的工序(基于原始chromosome)
Map
<
Integer
,
Entry
>
originalPositionIndex
=
buildPositionToEntryIndex
(
chromosome
,
entrys
);
Entry
opToMove
=
originalPositionIndex
.
get
(
pos
);
if
(
opToMove
==
null
)
{
return
neighbor
;
}
// 找到最远可以插入的位置(不打破优先级)
int
targetPos
=
Math
.
max
(
0
,
pos
-
steps
);
int
finalTargetPos
=
pos
;
for
(
int
i
=
pos
-
1
;
i
>=
targetPos
;
i
--)
{
// 计算加权能量差
Entry
leftOp
=
originalPositionIndex
.
get
(
i
);
double
diff
=
0
;
if
(
leftOp
!=
null
&&
opToMove
.
getGroupId
()
==
leftOp
.
getGroupId
())
{
for
(
int
i
=
0
;
i
<
neighborFitness
.
length
;
i
++)
{
break
;
diff
+=
(
neighborFitness
[
i
]
-
currentFitness
[
i
]);
}
if
(
leftOp
!=
null
&&
Math
.
abs
(
leftOp
.
getPriority
()
-
opToMove
.
getPriority
())
>
0.001
)
{
break
;
}
finalTargetPos
=
i
;
}
}
return
diff
;
if
(
finalTargetPos
==
pos
)
{
return
neighbor
;
}
}
// 执行插入:移除原位置,插入到目标位置
int
value
=
os
.
remove
(
pos
);
os
.
add
(
finalTargetPos
,
value
);
neighbor
.
setOperationSequencing
(
os
);
return
neighbor
;
}
/**
* 随机生成邻域解(兜底策略)
*/
private
Chromosome
generateRandomNeighbor
(
Chromosome
chromosome
,
Map
<
String
,
Entry
>
entrys
)
{
int
neighborType
=
rnd
.
nextInt
(
4
);
switch
(
neighborType
)
{
case
0
:
return
generateSwapNeighbor
(
chromosome
,
entrys
);
case
1
:
return
generateReverseNeighbor
(
chromosome
,
entrys
);
case
2
:
return
generateInsertNeighbor
(
chromosome
,
entrys
);
case
3
:
return
generateMachineChangeNeighbor
(
chromosome
);
default
:
return
generateSwapNeighbor
(
chromosome
,
entrys
);
}
}
/**
/**
*
生成交换邻域解 - 只在相同优先级的工序之间交换
*
按优先级分组工序
*/
*/
private
Chromosome
generateSwapNeighbor
(
Chromosome
chromosome
,
Map
<
String
,
Entry
>
entrys
)
{
private
Map
<
Double
,
List
<
Entry
>>
groupOperationsByPriority
()
{
Chromosome
neighbor
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
Map
<
Double
,
List
<
Entry
>>
groups
=
new
HashMap
<>();
List
<
Integer
>
os
=
neighbor
.
getOperationSequencing
();
for
(
Entry
op
:
allOperations
)
{
if
(
os
.
size
()
>=
2
)
{
double
priority
=
op
.
getPriority
();
Map
<
Integer
,
Entry
>
positionIndex
=
buildPositionToEntryIndex
(
neighbor
,
entrys
);
groups
.
computeIfAbsent
(
priority
,
k
->
new
ArrayList
<>()).
add
(
op
);
int
maxAttempts
=
50
;
for
(
int
attempt
=
0
;
attempt
<
maxAttempts
;
attempt
++)
{
int
idx1
=
rnd
.
nextInt
(
os
.
size
());
int
idx2
=
rnd
.
nextInt
(
os
.
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
)
{
java
.
util
.
Collections
.
swap
(
os
,
idx1
,
idx2
);
neighbor
.
setOperationSequencing
(
os
);
break
;
}
}
}
}
return
neighbor
;
}
}
/**
// 过滤掉:设备只有一个且只有一个GroupId的优先级组
* 生成反转邻域解 - 只反转相同优先级的连续工序
Map
<
Double
,
List
<
Entry
>>
filteredGroups
=
new
HashMap
<>();
*/
for
(
Map
.
Entry
<
Double
,
List
<
Entry
>>
entry
:
groups
.
entrySet
())
{
private
Chromosome
generateReverseNeighbor
(
Chromosome
chromosome
,
Map
<
String
,
Entry
>
entrys
)
{
List
<
Entry
>
ops
=
entry
.
getValue
();
Chromosome
neighbor
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
List
<
Integer
>
os
=
neighbor
.
getOperationSequencing
();
if
(
os
.
size
()
>=
2
)
{
Map
<
Integer
,
Entry
>
positionIndex
=
buildPositionToEntryIndex
(
neighbor
,
entrys
);
int
maxAttempts
=
50
;
for
(
int
attempt
=
0
;
attempt
<
maxAttempts
;
attempt
++)
{
int
start
=
rnd
.
nextInt
(
os
.
size
());
int
end
=
rnd
.
nextInt
(
os
.
size
());
if
(
end
<=
start
)
continue
;
Entry
startOp
=
positionIndex
.
get
(
start
);
// 检查是否所有工序都只有一个设备选项
if
(
startOp
==
null
)
continue
;
boolean
allSingleMachine
=
ops
.
stream
()
.
allMatch
(
op
->
op
.
getMachineOptions
().
size
()
<=
1
);
double
priority
=
startOp
.
getPriority
();
// 检查是否只有一个GroupId
boolean
allSamePriority
=
true
;
Set
<
Integer
>
groupIds
=
ops
.
stream
()
.
map
(
Entry:
:
getGroupId
)
.
collect
(
Collectors
.
toSet
());
for
(
int
i
=
start
;
i
<=
end
;
i
++)
{
// 如果两个条件都满足,过滤掉这个优先级组
Entry
op
=
positionIndex
.
get
(
i
);
if
(!(
allSingleMachine
&&
groupIds
.
size
()
<=
1
))
{
if
(
op
==
null
||
Math
.
abs
(
op
.
getPriority
()
-
priority
)
>
0.001
)
{
filteredGroups
.
put
(
entry
.
getKey
(),
ops
);
allSamePriority
=
false
;
break
;
}
}
}
}
if
(
allSamePriority
)
{
return
filteredGroups
;
java
.
util
.
Collections
.
reverse
(
os
.
subList
(
start
,
end
+
1
));
neighbor
.
setOperationSequencing
(
os
);
break
;
}
}
}
return
neighbor
;
}
}
/**
/**
*
生成插入邻域解 - 只插入到相同优先级的位置
*
构建Entry索引:op.getGroupId() + "_" + op.getSequence() -> Entry
*/
*/
private
Chromosome
generateInsertNeighbor
(
Chromosome
chromosome
,
Map
<
String
,
Entry
>
entrys
)
{
private
Map
<
Integer
,
Object
>
buildEntryKey
()
{
Chromosome
neighbor
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
Map
<
Integer
,
Object
>
index0
=
new
HashMap
<>();
List
<
Integer
>
os
=
neighbor
.
getOperationSequencing
();
Map
<
String
,
Entry
>
index
=
new
HashMap
<>();
if
(
os
.
size
()
>=
2
)
{
Map
<
Integer
,
Entry
>
index2
=
new
HashMap
<>();
Map
<
Integer
,
Entry
>
positionIndex
=
buildPositionToEntryIndex
(
neighbor
,
entrys
);
List
<
Entry
>
allOps
=
this
.
allOperations
;
int
maxAttempts
=
50
;
for
(
int
attempt
=
0
;
attempt
<
maxAttempts
;
attempt
++)
{
int
idx1
=
rnd
.
nextInt
(
os
.
size
());
int
idx2
=
rnd
.
nextInt
(
os
.
size
());
if
(
idx1
==
idx2
)
continue
;
Entry
op1
=
positionIndex
.
get
(
idx1
);
for
(
Entry
op
:
allOps
)
{
Entry
op2
=
positionIndex
.
get
(
idx2
);
String
key
=
op
.
getGroupId
()
+
"_"
+
op
.
getSequence
(
);
if
(
op1
!=
null
&&
op2
!=
null
)
{
index
.
put
(
key
,
op
);
if
(
Math
.
abs
(
op1
.
getPriority
()
-
op2
.
getPriority
())
<
0.001
)
{
index2
.
put
(
op
.
getId
(),
op
);
int
value
=
os
.
remove
(
idx1
);
os
.
add
(
idx2
,
value
);
neighbor
.
setOperationSequencing
(
os
);
break
;
}
}
}
}
}
return
neighbor
;
index0
.
put
(
1
,
index
);
index0
.
put
(
2
,
index2
);
return
index0
;
}
}
/**
/**
*
生成机器选择邻域解 - 不受优先级限制
*
解码染色体
*/
*/
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
=
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
);
}
}
if
(!
availableMachines
.
isEmpty
())
{
int
newMachineSeq
=
availableMachines
.
get
(
rnd
.
nextInt
(
availableMachines
.
size
()));
ms
.
set
(
idx
,
newMachineSeq
);
neighbor
.
setMachineSelection
(
ms
);
}
}
}
return
neighbor
;
}
/**
/**
* 解码染色体
* 解码染色体
*/
*/
...
@@ -847,24 +496,35 @@ private Map<String, Entry> entrys;
...
@@ -847,24 +496,35 @@ private Map<String, Entry> entrys;
// 假设Machine类有拷贝方法,或使用MapStruct等工具进行映射
// 假设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多层次比较)
* 比较两个染色体的优劣(基于fitnessLevel多层次比较)
*/
*/
private
boolean
isBetter
(
Chromosome
c1
,
Chromosome
c2
)
{
private
boolean
isBetter
(
Chromosome
c1
,
Chromosome
c2
)
{
for
(
int
i
=
0
;
i
<
c1
.
getFitnessLevel
().
length
;
i
++)
{
return
fitnessCalculator
.
isBetter
(
c1
,
c2
);
double
[]
Fitness1
=
c1
.
getFitnessLevel
();
double
[]
Fitness2
=
c2
.
getFitnessLevel
();
if
(
Fitness1
[
i
]
>
Fitness2
[
i
])
{
return
true
;
}
}
return
false
;
}
}
private
int
Getbest
(
List
<
Chromosome
>
candidates
,
Chromosome
best
)
{
private
int
Getbest
(
List
<
Chromosome
>
candidates
,
Chromosome
best
)
{
// 找出最佳候选方案
// 找出最佳候选方案
...
...
src/main/java/com/aps/service/Algorithm/TabuSearch.java
View file @
f2a1529b
package
com
.
aps
.
service
.
Algorithm
;
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.common.util.ProductionDeepCopyUtil
;
import
com.aps.entity.Algorithm.*
;
import
com.aps.entity.Algorithm.*
;
import
com.aps.entity.
basic.Entry
;
import
com.aps.entity.
Algorithm.IDAndChildID.GroupResult
;
import
com.aps.entity.basic.
GlobalParam
;
import
com.aps.entity.basic.
*
;
import
java.util.*
;
import
java.util.*
;
import
java.util.concurrent.CopyOnWriteArrayList
;
/**
/**
* 禁忌搜索算法
* 禁忌搜索算法
*/
*/
public
class
TabuSearch
{
public
class
TabuSearch
{
private
final
Random
rnd
=
new
Random
();
private
GlobalParam
globalParam
;
private
List
<
Entry
>
allOperations
;
private
List
<
GlobalOperationInfo
>
globalOpList
;
private
FitnessCalculator
fitnessCalculator
;
private
ObjectiveWeights
objectiveWeights
;
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
<
Chromosome
>
tabuList
;
private
List
<
String
>
tabuList
;
private
int
tabuListSize
=
50
;
private
int
tabuListSize
=
50
;
public
TabuSearch
(
GlobalParam
globalParam
,
List
<
Entry
>
allOperations
,
List
<
GlobalOperationInfo
>
globalOpList
,
FitnessCalculator
fitnessCalculator
,
ObjectiveWeights
objectiveWeights
)
{
private
List
<
Machine
>
cachedMachines
;
this
.
globalParam
=
globalParam
;
private
List
<
Order
>
cachedOrders
;
this
.
allOperations
=
allOperations
;
private
List
<
GroupResult
>
cachedEntryRel
;
this
.
globalOpList
=
globalOpList
;
private
List
<
Material
>
cachedMaterials
;
this
.
fitnessCalculator
=
fitnessCalculator
;
private
List
<
Entry
>
cachedAllOperations
;
this
.
objectiveWeights
=
objectiveWeights
;
// 渴望准则:记录最优解的 fitness
private
double
[]
bestFitness
;
public
TabuSearch
(
List
<
Entry
>
allOperations
,
List
<
Order
>
orders
,
List
<
Material
>
materials
,
List
<
GroupResult
>
entryRel
,
FitnessCalculator
_fitnessCalculator
)
{
this
.
tabuList
=
new
ArrayList
<>();
this
.
tabuList
=
new
ArrayList
<>();
// 工序越多,禁忌表越长(适配1000+工序)
// 工序越多,禁忌表越长(适配1000+工序)
this
.
tabuListSize
=
Math
.
min
(
50
,
allOperations
.
size
()
/
30
);
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
,
GeneticDecoder
decoder
,
ScheduleParams
param
)
{
public
Chromosome
search
(
Chromosome
chromosome
,
VariableNeighborhoodSearch
vns
,
GeneticDecoder
decoder
,
List
<
Machine
>
machines
)
{
log
(
"禁忌搜索 - 开始执行"
,
true
);
Chromosome
current
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
Chromosome
current
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
Chromosome
best
=
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
iterations
=
0
;
int
maxIterations
=
100
0
;
int
improveCount
=
0
;
int
noImprovementCount
=
0
;
int
noImprovementCount
=
0
;
int
maxNoImprovement
=
100
;
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%改进率阈值
while
(
iterations
<
maxIterations
&&
noImprovementCount
<
maxNoImprovement
)
{
// 多样性参数
// 生成邻域解
int
diversificationInterval
=
20
;
// 每20次迭代尝试一次多样化
List
<
Chromosome
>
neighbors
=
generateNeighbors
(
current
)
;
int
lastDiversificationIteration
=
0
;
// 过滤禁忌解
log
(
String
.
format
(
"禁忌搜索 - 参数:最大迭代=%d, 最大无改进=%d"
,
maxIterations
,
maxNoImprovement
));
List
<
Chromosome
>
validNeighbors
=
filterTabuSolutions
(
neighbors
);
// 评估所有邻域解
for
(
int
i
=
0
;
i
<
maxIterations
;
i
++)
{
Chromosome
bestNeighbor
=
null
;
iterations
++;
double
bestNeighborFitness
=
Double
.
NEGATIVE_INFINITY
;
// 使用 VNS 生成邻域解(成功率排序后的策略)
Chromosome
neighbor
=
vns
.
generateNeighbor
(
current
);
for
(
Chromosome
neighbor
:
validNeighbors
)
{
if
(
neighbor
==
null
)
{
decode
(
decoder
,
neighbor
,
param
);
log
(
"禁忌搜索 - 生成邻居失败,跳过"
);
if
(
neighbor
.
getFitness
()
>
bestNeighborFitness
)
{
noImprovementCount
++;
bestNeighborFitness
=
neighbor
.
getFitness
();
// 记录无改进
bestNeighbor
=
neighbor
;
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
;
}
}
if
(
bestNeighbor
!=
null
)
{
// 添加到禁忌表(无论是否接受都先记下来)
// 更新当前解
addToTabuList
(
neighborGeneStr
);
current
=
bestNeighbor
;
// 更新禁忌表
boolean
accept
=
false
;
addToTabuList
(
current
);
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
(
isBetter
(
current
,
best
))
{
if
(
isBetterThanBest
)
{
best
=
current
;
best
=
ProductionDeepCopyUtil
.
deepCopy
(
current
,
Chromosome
.
class
);
this
.
bestFitness
=
best
.
getFitnessLevel
().
clone
();
writeKpi
(
best
);
noImprovementCount
=
0
;
noImprovementCount
=
0
;
improveCount
++;
improvedThisIteration
=
true
;
logTabuImprovement
(
best
,
initialFitnessLevel
,
initialFitness
,
iterations
);
log
(
String
.
format
(
"禁忌搜索 - 找到更好解,迭代=%d"
,
iterations
),
true
);
}
else
if
(
isBetterThanCurrent
)
{
// 比当前解好但没有比最优解好
noImprovementCount
=
0
;
improvedThisIteration
=
true
;
}
else
{
}
else
{
// 没有改进
noImprovementCount
++;
noImprovementCount
++;
}
}
}
else
{
// 不接受,无改进计数+1
noImprovementCount
++;
}
}
iterations
++;
// 记录本次改进情况
if
(
iterations
<=
stagnantWindow
)
{
recentImprovements
[
iterations
-
1
]
=
improvedThisIteration
?
1
:
0
;
}
}
return
best
;
// 每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
=
""
;
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
;
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
);
private
List
<
Chromosome
>
filterTabuSolutions
(
List
<
Chromosome
>
neighbors
)
{
break
;
List
<
Chromosome
>
validNeighbors
=
new
ArrayList
<>();
for
(
Chromosome
neighbor
:
neighbors
)
{
if
(!
isTabu
(
neighbor
))
{
validNeighbors
.
add
(
neighbor
);
}
}
}
}
// 如果没有有效邻域解,返回所有邻域解
logTabuFinalSummary
(
best
,
initialFitnessLevel
,
initialFitness
,
iterations
,
improveCount
);
if
(
validNeighbors
.
isEmpty
())
{
log
(
String
.
format
(
"禁忌搜索 - 结束,总迭代=%d"
,
iterations
),
true
);
return
neighbors
;
return
best
;
}
}
private
void
writeKpi
(
Chromosome
chromosome
)
{
String
fitness
=
""
;
double
[]
fitness1
=
chromosome
.
getFitnessLevel
();
for
(
int
i
=
0
;
i
<
fitness1
.
length
;
i
++)
{
return
validNeighbors
;
fitness
+=
fitness1
[
i
]
+
","
;
}
}
log
(
String
.
format
(
"变邻域搜索 - kpi:%s"
,
fitness
),
true
);
}
/**
/**
*
检查解是否在禁忌表中
*
记录禁忌搜索改进详情
*/
*/
private
boolean
isTabu
(
Chromosome
chromosome
)
{
private
void
logTabuImprovement
(
Chromosome
best
,
double
[]
initialFitnessLevel
,
double
initialFitness
,
int
iteration
)
{
for
(
Chromosome
tabuChromosome
:
tabuList
)
{
StringBuilder
sb
=
new
StringBuilder
(
"禁忌搜索 - 改进详情: 迭代"
+
iteration
+
", "
);
if
(
chromosome
.
getGeneStr
().
equals
(
tabuChromosome
.
getGeneStr
()))
{
double
[]
currentFitness
=
best
.
getFitnessLevel
();
return
true
;
}
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
));
}
}
return
false
;
double
totalImprovement
=
best
.
getFitness
()
-
initialFitness
;
sb
.
append
(
String
.
format
(
"总Fitness: %.4f→%.4f(+%.4f)"
,
initialFitness
,
best
.
getFitness
(),
totalImprovement
));
log
(
sb
.
toString
());
}
}
/**
/**
*
添加解到禁忌表
*
计算最近改进率
*/
*/
private
void
addToTabuList
(
Chromosome
chromosom
e
)
{
private
double
calculateRecentImprovementRate
(
int
[]
recentImprovements
,
int
windowSiz
e
)
{
tabuList
.
add
(
chromosome
)
;
int
improveCount
=
0
;
if
(
tabuList
.
size
()
>
tabuListSize
)
{
for
(
int
i
=
0
;
i
<
windowSize
;
i
++
)
{
tabuList
.
remove
(
0
)
;
improveCount
+=
recentImprovements
[
i
]
;
}
}
return
(
double
)
improveCount
/
windowSize
;
}
}
/**
/**
*
生成交换邻域解
*
记录禁忌搜索最终总结
*/
*/
private
Chromosome
generateSwapNeighbor
(
Chromosome
chromosome
)
{
private
void
logTabuFinalSummary
(
Chromosome
best
,
double
[]
initialFitnessLevel
,
double
initialFitness
,
Chromosome
neighbor
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
int
totalIterations
,
int
improveCount
)
{
List
<
Integer
>
os
=
neighbor
.
getOperationSequencing
();
StringBuilder
sb
=
new
StringBuilder
(
"禁忌搜索 - 最终总结: "
);
if
(
os
.
size
()
>=
2
)
{
double
[]
currentFitness
=
best
.
getFitnessLevel
();
int
idx1
=
rnd
.
nextInt
(
os
.
size
());
int
idx2
=
rnd
.
nextInt
(
os
.
size
());
sb
.
append
(
String
.
format
(
"总迭代%d次, 成功改进%d次, 改进率%.2f%%. "
,
while
(
idx2
==
idx1
)
{
totalIterations
,
improveCount
,
totalIterations
>
0
?
(
double
)
improveCount
/
totalIterations
*
100
:
0
));
idx2
=
rnd
.
nextInt
(
os
.
size
());
}
for
(
int
i
=
0
;
i
<
currentFitness
.
length
;
i
++)
{
Collections
.
swap
(
os
,
idx1
,
idx2
);
double
improvement
=
currentFitness
[
i
]
-
initialFitnessLevel
[
i
];
neighbor
.
setOperationSequencing
(
os
);
sb
.
append
(
String
.
format
(
"KPI%d: %.4f→%.4f(%.2f%%) "
,
i
+
1
,
initialFitnessLevel
[
i
],
currentFitness
[
i
],
}
initialFitnessLevel
[
i
]
>
0
?
improvement
/
initialFitnessLevel
[
i
]
*
100
:
0
));
return
neighbor
;
}
}
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
Chromosome
generateReverseNeighbor
(
Chromosome
chromosome
)
{
public
boolean
isTabu
(
String
GeneStr
)
{
Chromosome
neighbor
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
List
<
Integer
>
os
=
neighbor
.
getOperationSequencing
();
return
tabuList
.
contains
(
GeneStr
);
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
;
}
}
/**
/**
*
生成插入邻域解
*
添加解到禁忌表(FIFO策略)
*/
*/
private
Chromosome
generateInsertNeighbor
(
Chromosome
chromosome
)
{
public
void
addToTabuList
(
String
geneStr
)
{
Chromosome
neighbor
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
tabuList
.
add
(
geneStr
);
List
<
Integer
>
os
=
neighbor
.
getOperationSequencing
();
if
(
tabuList
.
size
()
>
tabuListSize
)
{
if
(
os
.
size
()
>=
2
)
{
// 移除最早加入的禁忌解
int
idx1
=
rnd
.
nextInt
(
os
.
size
());
tabuList
.
remove
(
0
);
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
)
{
private
void
decode
(
GeneticDecoder
decoder
,
Chromosome
chromosome
,
List
<
Machine
>
machines
)
{
int
currentMachineSeq
=
ms
.
get
(
idx
);
chromosome
.
setResult
(
new
CopyOnWriteArrayList
<>());
List
<
Integer
>
availableMachines
=
new
ArrayList
<>();
for
(
int
i
=
1
;
i
<=
op
.
getMachineOptions
().
size
();
i
++)
{
if
(
i
!=
currentMachineSeq
)
{
availableMachines
.
add
(
i
);
}
}
if
(!
availableMachines
.
isEmpty
())
{
// 缓存 Machine 列表(第一次调用时缓存)
int
newMachineSeq
=
availableMachines
.
get
(
rnd
.
nextInt
(
availableMachines
.
size
()));
if
(
cachedMachines
==
null
)
{
ms
.
set
(
idx
,
newMachineSeq
);
cachedMachines
=
ProductionDeepCopyUtil
.
deepCopyList
(
machines
,
Machine
.
class
);
neighbor
.
setMachineSelection
(
ms
);
}
}
}
return
neighbor
;
}
}
/**
// 使用缓存的列表,避免重复深拷贝
* 解码染色体
chromosome
.
setMachines
(
ProductionDeepCopyUtil
.
deepCopyList
(
cachedMachines
,
Machine
.
class
));
*/
chromosome
.
setOrders
(
ProductionDeepCopyUtil
.
deepCopyList
(
new
CopyOnWriteArrayList
<>(
cachedOrders
),
Order
.
class
));
private
void
decode
(
GeneticDecoder
decoder
,
Chromosome
chromosome
,
ScheduleParams
param
)
{
chromosome
.
setOperatRel
(
ProductionDeepCopyUtil
.
deepCopyList
(
new
CopyOnWriteArrayList
<>(
cachedEntryRel
),
GroupResult
.
class
));
chromosome
.
setResult
(
new
java
.
util
.
concurrent
.
CopyOnWriteArrayList
<>());
chromosome
.
setMaterials
(
ProductionDeepCopyUtil
.
deepCopyList
(
cachedMaterials
,
Material
.
class
));
decoder
.
decodeChromosomeWithCache
(
chromosome
);
chromosome
.
setAllOperations
(
ProductionDeepCopyUtil
.
deepCopyList
(
new
CopyOnWriteArrayList
<>(
cachedAllOperations
),
Entry
.
class
));
if
(
chromosome
.
getFitness
()
==
0
)
{
chromosome
.
setFitness
(
fitnessCalculator
.
calculateFitness
(
chromosome
,
objectiveWeights
));
// 加载锁定工单到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
)
{
private
boolean
isBetter
(
Chromosome
c1
,
Chromosome
c2
)
{
return
c1
.
getFitness
()
>
c2
.
getFitness
(
);
return
fitnessCalculator
.
isBetter
(
c1
,
c2
);
}
}
}
}
\ No newline at end of file
src/main/java/com/aps/service/Algorithm/TabuSearchWithSA.java
deleted
100644 → 0
View file @
bb00017a
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 @
f2a1529b
This source diff could not be displayed because it is too large. You can
view the blob
instead.
src/main/java/com/aps/service/plan/PlanResultService.java
View file @
f2a1529b
...
@@ -222,7 +222,7 @@ public class PlanResultService {
...
@@ -222,7 +222,7 @@ public class PlanResultService {
lockedOrderProcessorService
.
markLockedOrdersOccupiedTime
(
machines
,
timeConfig
.
getBaseTime
());
lockedOrderProcessorService
.
markLockedOrdersOccupiedTime
(
machines
,
timeConfig
.
getBaseTime
());
// 5. 执行调度算法
// 5. 执行调度算法
GeneticAlgorithm
scheduler
=
new
Genetic
Algorithm
(
globalParam
,
machines
,
orders
,
Materials1
,
materialIds
,
machineScheduler
,
entryRel
,
materialRequirementService
,
_sceneService
,
SceneId
);
//new GeneticAlgorithm(products, machines, orders, machineScheduler);
HybridAlgorithm
scheduler
=
new
Hybrid
Algorithm
(
globalParam
,
machines
,
orders
,
Materials1
,
materialIds
,
machineScheduler
,
entryRel
,
materialRequirementService
,
_sceneService
,
SceneId
);
//new GeneticAlgorithm(products, machines, orders, machineScheduler);
param
.
initAdaptiveParams
(
entrys
.
size
());
param
.
initAdaptiveParams
(
entrys
.
size
());
double
[]
customWeights
=
new
double
[]
{
0.4
,
0.1
,
0.1
,
0.1
,
0.3
};
// 延迟时间权重提升到0.5
double
[]
customWeights
=
new
double
[]
{
0.4
,
0.1
,
0.1
,
0.1
,
0.3
};
// 延迟时间权重提升到0.5
//完工时间、总流程时间、总换型时间、机器负载标准差、延迟时间
//完工时间、总流程时间、总换型时间、机器负载标准差、延迟时间
...
@@ -238,7 +238,7 @@ public class PlanResultService {
...
@@ -238,7 +238,7 @@ public class PlanResultService {
_sceneService
.
saveChromosomeToFile
(
chromosome
,
SceneId
);
_sceneService
.
saveChromosomeToFile
(
chromosome
,
SceneId
);
WriteScheduleSummary
(
chromosome
);
//
WriteScheduleSummary(chromosome);
return
chromosome
;
return
chromosome
;
...
...
src/main/java/com/aps/service/plan/SceneService.java
View file @
f2a1529b
...
@@ -132,7 +132,7 @@ public class SceneService {
...
@@ -132,7 +132,7 @@ public class SceneService {
try
{
try
{
ObjectMapper
objectMapper
=
createObjectMapper
();
ObjectMapper
objectMapper
=
createObjectMapper
();
SceneChromsome
sceneChromsome
=(
SceneChromsome
)
redisUtils
.
get
(
"SceneId."
+
sceneId
);
SceneChromsome
sceneChromsome
=
null
;
//
(SceneChromsome)redisUtils.get("SceneId."+sceneId);
if
(
sceneChromsome
==
null
)
if
(
sceneChromsome
==
null
)
{
{
sceneChromsome
=
new
SceneChromsome
();
sceneChromsome
=
new
SceneChromsome
();
...
@@ -163,7 +163,7 @@ public class SceneService {
...
@@ -163,7 +163,7 @@ public class SceneService {
sceneChromsome
.
getSceneDetails
().
add
(
sceneDetail
);
sceneChromsome
.
getSceneDetails
().
add
(
sceneDetail
);
redisUtils
.
set
(
"SceneId."
+
sceneId
,
sceneChromsome
);
//
redisUtils.set("SceneId."+sceneId,sceneChromsome);
File
file
=
getChromosomeFile
(
sceneId
,
sceneChromsome
.
getVersion
().
toString
());
File
file
=
getChromosomeFile
(
sceneId
,
sceneChromsome
.
getVersion
().
toString
());
...
...
src/test/java/com/aps/demo/PlanResultServiceTest.java
View file @
f2a1529b
...
@@ -39,7 +39,8 @@ public class PlanResultServiceTest {
...
@@ -39,7 +39,8 @@ public class PlanResultServiceTest {
// TestSortService sortService=new TestSortService();
// TestSortService sortService=new TestSortService();
// sortService.test1();
// sortService.test1();
// nsgaiiUtils.Test();
// nsgaiiUtils.Test();
planResultService
.
execute2
(
"0428340BB4F540938F1FB5599F03E8A4"
);
//2000
planResultService
.
execute2
(
"08B1D87FE1B84ECDBAC2E546DDB6FB81"
);
//2000
// planResultService.execute2("0428340BB4F540938F1FB5599F03E8A4");//2000
// planResultService.execute2("C8B533BD8944405B9A2F8823C575C204");//500
// planResultService.execute2("C8B533BD8944405B9A2F8823C575C204");//500
// planResultService.execute2("EFDD34E4B5BC434BAEAE6A84DFCD4E7B");//20
// planResultService.execute2("EFDD34E4B5BC434BAEAE6A84DFCD4E7B");//20
// planResultService.execute2("00E0C5D3E4AD4F36B56C39395906618D");
// 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