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
aba10b46
Commit
aba10b46
authored
Nov 28, 2025
by
DESKTOP-VKRD9QF\Administration
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
修改速度计算
parent
01953779
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
65284 additions
and
0 deletions
+65284
-0
schedule_log.txt
schedule_log.txt
+63980
-0
AlgorithmScheduler8.java
src/main/java/com/aps/service/plan/AlgorithmScheduler8.java
+1304
-0
No files found.
schedule_log.txt
View file @
aba10b46
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/AlgorithmScheduler8.java
0 → 100644
View file @
aba10b46
package
com
.
aps
.
service
.
plan
;
import
com.aps.common.util.FileHelper
;
import
com.aps.entity.basic.*
;
import
java.time.LocalDateTime
;
import
java.time.temporal.ChronoUnit
;
import
java.util.*
;
import
java.util.stream.Collectors
;
public
class
AlgorithmScheduler8
{
private
final
List
<
Product
>
_products
;
private
final
List
<
Machine
>
_machines
;
private
final
List
<
Order
>
_orders
;
private
final
Random
_random
;
private
final
MachineSchedulerService
_machineScheduler
;
private
int
_populationSize
=
100
;
private
double
_crossoverRate
=
0.8
;
private
double
_mutationRate
=
0.1
;
private
int
_maxGenerations
=
500
;
private
int
_elitismCount
=
5
;
private
final
LocalDateTime
baseTime
=
LocalDateTime
.
of
(
2025
,
10
,
1
,
0
,
0
,
0
);
// 是否平滑换型参数
private
boolean
_smoothSetup
=
false
;
// 默认true,不占用设备时长
public
AlgorithmScheduler8
(
List
<
Product
>
products
,
List
<
Machine
>
machines
,
List
<
Order
>
orders
,
MachineSchedulerService
machineScheduler
)
{
this
(
products
,
machines
,
orders
,
machineScheduler
,
false
);
}
public
AlgorithmScheduler8
(
List
<
Product
>
products
,
List
<
Machine
>
machines
,
List
<
Order
>
orders
,
MachineSchedulerService
machineScheduler
,
boolean
smoothSetup
)
{
this
.
_products
=
deepCopyProductList
(
products
);
this
.
_machines
=
deepCopyMachineList
(
machines
);
this
.
_orders
=
deepCopyOrderList
(
orders
);
this
.
_machineScheduler
=
machineScheduler
;
this
.
_random
=
new
Random
();
}
public
void
setSmoothSetup
(
boolean
smoothSetup
)
{
this
.
_smoothSetup
=
smoothSetup
;
}
public
boolean
isSmoothSetup
()
{
return
_smoothSetup
;
}
public
ScheduleChromosome
Run
()
{
List
<
ScheduleChromosome
>
population
=
InitializePopulation
();
ScheduleChromosome
bestSolution
=
null
;
ScheduleChromosome
currentBest
=
null
;
double
bestFitness
=
Double
.
MIN_VALUE
;
currentBest
=
population
.
stream
()
.
max
(
Comparator
.
comparingDouble
(
ScheduleChromosome:
:
getFitness
))
.
orElse
(
null
);
if
(
currentBest
!=
null
)
{
bestFitness
=
currentBest
.
getFitness
();
bestSolution
=
deepCopyScheduleChromosome
(
currentBest
);
}
return
bestSolution
;
}
public
List
<
ScheduleChromosome
>
RunAll
()
{
List
<
ScheduleChromosome
>
scheduleChromosomes
=
InitializePopulation
();
return
scheduleChromosomes
;
}
private
List
<
ScheduleChromosome
>
InitializePopulation
()
{
List
<
ScheduleChromosome
>
population
=
new
ArrayList
<>();
System
.
out
.
println
(
"开始初始化种群,目标大小: "
+
_populationSize
);
System
.
out
.
println
(
"换型模式: "
+
(
_smoothSetup
?
"平滑模式(换型不占用设备时长)"
:
"标准模式(换型占用设备时长)"
));
for
(
int
i
=
0
;
i
<
_populationSize
;
i
++)
{
ScheduleChromosome
chromosome
=
new
ScheduleChromosome
(
baseTime
);
chromosome
.
setGenes
(
new
ArrayList
<>());
chromosome
.
setObjectiveValues
(
new
HashMap
<>());
chromosome
.
setOrders
(
deepCopyOrderList
(
_orders
));
chromosome
.
setMachines
(
deepCopyMachineList
(
_machines
));
// Reset machine states for each new chromosome
for
(
Machine
machine
:
chromosome
.
getMachines
())
{
machine
.
setEarliestTime
(
0
);
machine
.
setTotalTaskTime
(
0
);
}
System
.
out
.
println
(
"=== 初始化染色体 "
+
(
i
+
1
)
+
" ==="
);
// 为每个订单分配工序
for
(
Order
order
:
_orders
)
{
Product
product
=
_products
.
stream
()
.
filter
(
p
->
p
.
getId
()
==
order
.
getProductId
())
.
findFirst
()
.
orElseThrow
(()
->
new
NoSuchElementException
(
"Product not found: "
+
order
.
getProductId
()));
int
remainingQuantity
=
(
int
)
order
.
getQuantity
();
System
.
out
.
println
(
"处理订单 "
+
order
.
getId
()
+
", 产品 "
+
product
.
getId
()
+
", 数量: "
+
remainingQuantity
);
// 订单拆分逻辑
while
(
remainingQuantity
>
0
)
{
int
batchSize
;
if
(
order
.
isCanSplit
()
&&
remainingQuantity
>
1
)
{
int
maxSplit
=
Math
.
min
(
remainingQuantity
,
Math
.
max
(
1
,
remainingQuantity
/
2
));
batchSize
=
_random
.
nextInt
(
maxSplit
)
+
1
;
}
else
{
batchSize
=
remainingQuantity
;
}
if
(
batchSize
>
remainingQuantity
)
{
batchSize
=
remainingQuantity
;
}
remainingQuantity
-=
batchSize
;
System
.
out
.
println
(
" 批次大小: "
+
batchSize
+
", 剩余数量: "
+
remainingQuantity
);
// 为当前批次记录每道工序的结束时间(包含后处理时间)
Map
<
Integer
,
Integer
>
operationEndTimes
=
new
HashMap
<>();
// 按工序顺序处理当前批次
List
<
Operation
>
sortedOperations
=
product
.
getOperations
().
stream
()
.
sorted
(
Comparator
.
comparingInt
(
Operation:
:
getSequence
))
.
collect
(
Collectors
.
toList
());
for
(
Operation
operation
:
sortedOperations
)
{
System
.
out
.
println
(
" 处理工序 "
+
operation
.
getId
()
+
" (序列: "
+
operation
.
getSequence
()
+
")"
);
// 获取前一道工序的结束时间(包含后处理时间)
int
prevOperationEndTime
=
operation
.
getId
()
>
1
?
operationEndTimes
.
getOrDefault
(
operation
.
getId
()
-
1
,
0
)
:
0
;
System
.
out
.
println
(
" 前序工序结束时间(含后处理): "
+
prevOperationEndTime
);
MachineOption
machineOption
;
Machine
machine
;
// 多设备选择逻辑
if
(
operation
.
getMachineOptions
().
size
()
>
1
)
{
Set
<
Long
>
machineIds
=
operation
.
getMachineOptions
().
stream
()
.
map
(
MachineOption:
:
getMachineId
)
.
collect
(
Collectors
.
toSet
());
List
<
Machine
>
availableMachines
=
chromosome
.
getMachines
().
stream
()
.
filter
(
t
->
machineIds
.
contains
(
t
.
getId
()))
.
collect
(
Collectors
.
toList
());
if
(!
availableMachines
.
isEmpty
())
{
Collections
.
shuffle
(
availableMachines
,
_random
);
machine
=
availableMachines
.
get
(
0
);
Machine
finalMachine
=
machine
;
machineOption
=
operation
.
getMachineOptions
().
stream
()
.
filter
(
t
->
t
.
getMachineId
()
==
finalMachine
.
getId
())
.
findFirst
()
.
orElseThrow
(()
->
new
NoSuchElementException
(
"MachineOption not found for machine: "
+
finalMachine
.
getId
()));
}
else
{
machine
=
chromosome
.
getMachines
().
stream
()
.
filter
(
t
->
machineIds
.
contains
(
t
.
getId
()))
.
sorted
(
Comparator
.
comparingInt
(
Machine:
:
getEarliestTime
)
.
thenComparingDouble
(
Machine:
:
getTotalTaskTime
)
.
thenComparing
(
t
->
_random
.
nextDouble
()))
.
findFirst
()
.
orElseThrow
(()
->
new
NoSuchElementException
(
"No available machine for operation: "
+
operation
.
getId
()));
Machine
finalMachine
=
machine
;
machineOption
=
operation
.
getMachineOptions
().
stream
()
.
filter
(
t
->
t
.
getMachineId
()
==
finalMachine
.
getId
())
.
findFirst
()
.
orElseThrow
(()
->
new
NoSuchElementException
(
"MachineOption not found for machine: "
+
finalMachine
.
getId
()));
}
}
else
{
machineOption
=
operation
.
getMachineOptions
().
get
(
0
);
MachineOption
finalMachineOption
=
machineOption
;
machine
=
chromosome
.
getMachines
().
stream
()
.
filter
(
m
->
m
.
getId
()
==
finalMachineOption
.
getMachineId
())
.
findFirst
()
.
orElseThrow
(()
->
new
NoSuchElementException
(
"Machine not found: "
+
finalMachineOption
.
getMachineId
()));
}
System
.
out
.
println
(
" 选择设备: "
+
machine
.
getId
()
+
", 机器选项: "
+
machineOption
.
getMachineId
());
int
processingTime
=
(
int
)
(
machineOption
.
getProcessingTime
()
*
batchSize
);
int
teardownTime
=
machineOption
.
getTeardownTime
();
int
preTime
=
machineOption
.
getPreTime
();
int
setupTime
=
calculateSetupTime
(
chromosome
.
getGenes
(),
order
,
machine
,
machineOption
);
System
.
out
.
println
(
" 处理时间: "
+
processingTime
+
", 后处理: "
+
teardownTime
+
", 前处理: "
+
preTime
+
", 换型: "
+
setupTime
);
// 根据换型模式计算总处理时间
int
totalProcessingTime
;
if
(
_smoothSetup
)
{
// 平滑模式:换型不占用设备时长
totalProcessingTime
=
processingTime
;
// 只计算主处理时间
System
.
out
.
println
(
" 平滑模式:换型时间 "
+
setupTime
+
" 分钟不占用设备时长"
);
}
else
{
// 标准模式:换型占用设备时长
totalProcessingTime
=
processingTime
+
setupTime
;
// 主处理+换型时间
System
.
out
.
println
(
" 标准模式:换型时间 "
+
setupTime
+
" 分钟占用设备时长"
);
}
// 前处理和后处理都不占用设备时长,只在工序间协调时考虑
System
.
out
.
println
(
" 前处理 "
+
preTime
+
" 分钟和后处理 "
+
teardownTime
+
" 分钟在非工作时间进行"
);
// 确定任务的最早开始时间(基于前一道工序的完整结束时间,包含后处理)
int
earliestStartTime
=
prevOperationEndTime
;
// 检查设备上是否有前一个任务
Gene
lastGeneOnMachine
=
chromosome
.
getGenes
().
stream
()
.
filter
(
g
->
g
.
getMachineId
()
==
machine
.
getId
())
.
max
(
Comparator
.
comparingInt
(
Gene:
:
getEndTime
))
.
orElse
(
null
);
if
(
lastGeneOnMachine
!=
null
)
{
// 设备上已有任务,当前任务必须在设备可用后开始
// 设备可用时间 = 前一个任务的主处理结束时间(后处理不占用设备)
int
machineAvailableTime
=
lastGeneOnMachine
.
getEndTime
();
if
(
setupTime
>
0
)
{
if
(
_smoothSetup
)
{
machineAvailableTime
+=
setupTime
;
// 平滑模式:换型在非工作时间进行,不额外占用设备时间
System
.
out
.
println
(
" 平滑模式换型:在非工作时间进行,设备可用时间不变"
);
}
else
{
// 标准模式:换型需要额外占用设备时间
machineAvailableTime
+=
setupTime
;
System
.
out
.
println
(
" 标准模式换型:需要额外占用设备 "
+
setupTime
+
" 分钟"
);
}
}
earliestStartTime
=
Math
.
max
(
earliestStartTime
,
machineAvailableTime
);
}
System
.
out
.
println
(
" 最终最早开始时间: "
+
earliestStartTime
+
" (前序工序结束含后处理: "
+
prevOperationEndTime
+
", 设备可用: "
+
(
lastGeneOnMachine
!=
null
?
lastGeneOnMachine
.
getEndTime
()
:
0
)
+
", 换型: "
+
setupTime
+
")"
);
// 根据换型模式调整处理时间
int
processingTimeForScheduling
;
if
(
_smoothSetup
)
{
// 平滑模式:只需要安排主处理时间
processingTimeForScheduling
=
processingTime
;
System
.
out
.
println
(
" 平滑模式:安排主处理时间 "
+
processingTime
+
" 分钟"
);
}
else
{
// 标准模式:需要安排主处理时间+换型时间
processingTimeForScheduling
=
processingTime
+
setupTime
;
System
.
out
.
println
(
" 标准模式:安排主处理+"
+
setupTime
+
"分钟换型="
+
processingTimeForScheduling
+
"分钟"
);
}
// 获取可用时间段(只考虑主处理和换型时间)
List
<
GeneDetail
>
geneDetails
=
GetNextAvailableTime
(
machine
,
earliestStartTime
,
-
1
,
processingTimeForScheduling
,
chromosome
.
getGenes
(),
false
,
true
);
if
(
geneDetails
.
isEmpty
())
{
System
.
out
.
println
(
" ⚠️ 未找到可用时间段,尝试调整时间"
);
// 尝试在当前时间基础上增加一些时间重新查找
geneDetails
=
GetNextAvailableTime
(
machine
,
earliestStartTime
+
60
,
-
1
,
processingTimeForScheduling
,
chromosome
.
getGenes
(),
false
,
true
);
}
int
startTime
=
geneDetails
.
stream
().
mapToInt
(
GeneDetail:
:
getStartTime
).
min
().
orElse
(
0
);
int
endTime
=
geneDetails
.
stream
().
mapToInt
(
GeneDetail:
:
getEndTime
).
max
().
orElse
(
0
);
if
(
startTime
==
0
&&
endTime
==
0
)
{
System
.
out
.
println
(
" ❌ 无法安排任务,跳过此工序"
);
continue
;
}
System
.
out
.
println
(
" 安排时间: "
+
ConvertTime
(
startTime
)
+
" - "
+
ConvertTime
(
endTime
)
+
" ("
+
(
endTime
-
startTime
)
+
"分钟)"
);
// 冲突检测和解决
final
int
finalStartTime
=
startTime
;
final
int
finalEndTime
=
endTime
;
Gene
conflictingGene
=
chromosome
.
getGenes
().
stream
()
.
filter
(
g
->
g
.
getMachineId
()
==
machine
.
getId
())
.
filter
(
g
->
(
finalStartTime
<
g
.
getEndTime
()
&&
finalEndTime
>
g
.
getStartTime
()))
.
findFirst
()
.
orElse
(
null
);
if
(
conflictingGene
!=
null
)
{
System
.
out
.
println
(
" ⚠️ 检测到时间冲突,重新调度"
);
int
conflictSetupStartTime
=
conflictingGene
.
getEndTime
();
int
conflictSetupTime
=
calculateSetupTimeForConflict
(
chromosome
.
getGenes
(),
order
,
machine
,
machineOption
,
conflictingGene
);
int
conflictEarliestStartTime
=
conflictSetupStartTime
+
conflictSetupTime
;
geneDetails
=
GetNextAvailableTime
(
machine
,
conflictEarliestStartTime
,
-
1
,
processingTimeForScheduling
,
chromosome
.
getGenes
(),
false
,
true
);
if
(!
geneDetails
.
isEmpty
())
{
startTime
=
geneDetails
.
stream
().
mapToInt
(
GeneDetail:
:
getStartTime
).
min
().
orElse
(
0
);
endTime
=
geneDetails
.
stream
().
mapToInt
(
GeneDetail:
:
getEndTime
).
max
().
orElse
(
0
);
System
.
out
.
println
(
" 重新安排时间: "
+
ConvertTime
(
startTime
)
+
" - "
+
ConvertTime
(
endTime
));
}
}
// 记录当前工序的结束时间(包含后处理时间)
int
currentOperationEndTime
=
endTime
+
teardownTime
;
operationEndTimes
.
put
(
operation
.
getId
(),
currentOperationEndTime
);
System
.
out
.
println
(
" 当前工序结束时间(含后处理): "
+
currentOperationEndTime
+
" (主处理结束: "
+
endTime
+
", 后处理: "
+
teardownTime
+
")"
);
// 更新设备状态(后处理不占用设备,所以设备可用时间只到主处理结束)
int
machineAvailableTime
=
endTime
;
machine
.
setEarliestTime
(
machineAvailableTime
);
machine
.
setTotalTaskTime
(
machine
.
getTotalTaskTime
()
+
totalProcessingTime
);
System
.
out
.
println
(
" 设备 "
+
machine
.
getId
()
+
" 下次可用时间: "
+
machineAvailableTime
);
// 创建基因
Gene
gene
=
new
Gene
();
gene
.
setOrderId
(
order
.
getId
());
gene
.
setProductId
(
order
.
getProductId
());
gene
.
setOperationId
(
operation
.
getId
());
gene
.
setMachineId
(
machine
.
getId
());
gene
.
setBatchSize
(
batchSize
);
gene
.
setSetupTime
(
setupTime
);
gene
.
setStartTime
(
startTime
);
gene
.
setEndTime
(
endTime
);
gene
.
setProcessingTime
(
processingTime
);
gene
.
setTeardownTime
(
teardownTime
);
gene
.
setPreTime
(
preTime
);
gene
.
setGeneDetails
(
deepCopyGeneDetailList
(
geneDetails
));
gene
.
setId
(
chromosome
.
getGenes
().
size
()
+
1
);
gene
.
setSequenceId
(
operation
.
getSequence
());
// 关键修复:根据换型模式设置开始时间
if
(!
_smoothSetup
&&
setupTime
>
0
)
{
// 标准模式:换型占用工作时间,开始时间不包含换型时间
gene
.
setAbsoluteSetupTime
(
calculateAbsoluteSetupTime
(
gene
,
machine
));
gene
.
setAbsoluteStartTime
(
calculateMainProcessingStartTime
(
machine
,
startTime
,
calculateAbsoluteSetupTime
(
gene
,
machine
),
geneDetails
)
);
}
else
{
gene
.
setAbsoluteStartTime
(
startTime
);
gene
.
setAbsoluteSetupTime
(
setupTime
);
}
chromosome
.
getGenes
().
add
(
gene
);
System
.
out
.
println
(
" ✅ 工序 "
+
operation
.
getId
()
+
" 安排完成"
);
}
System
.
out
.
println
(
" ✅ 批次 "
+
batchSize
+
" 处理完成"
);
}
}
population
.
add
(
chromosome
);
System
.
out
.
println
(
"✅ 染色体 "
+
(
i
+
1
)
+
" 初始化完成,基因数量: "
+
chromosome
.
getGenes
().
size
());
}
System
.
out
.
println
(
"生成种群大小: "
+
population
.
size
());
// 去重逻辑
Map
<
String
,
List
<
ScheduleChromosome
>>
grouped
=
population
.
stream
()
.
collect
(
Collectors
.
groupingBy
(
ScheduleChromosome:
:
getGenesStr
));
population
=
grouped
.
values
().
stream
()
.
map
(
group
->
group
.
get
(
0
))
.
collect
(
Collectors
.
toList
());
System
.
out
.
println
(
"去重后种群大小: "
+
population
.
size
());
// 调试输出染色体多样性
System
.
out
.
println
(
"染色体多样性分析:"
);
Map
<
String
,
Integer
>
keyCounts
=
new
HashMap
<>();
for
(
ScheduleChromosome
chrom
:
population
)
{
String
key
=
chrom
.
getGenesStr
();
keyCounts
.
put
(
key
,
keyCounts
.
getOrDefault
(
key
,
0
)
+
1
);
}
System
.
out
.
println
(
"唯一染色体数量: "
+
keyCounts
.
size
());
System
.
out
.
println
(
"染色体分布: "
+
keyCounts
);
// 并行计算适应度
population
.
parallelStream
().
forEach
(
this
::
CalculateFitness
);
// 打印摘要
population
.
forEach
(
this
::
WriteScheduleSummary
);
return
population
;
}
private
void
CalculateFitness
(
ScheduleChromosome
chromosome
)
{
// 1. 最大完工时间
double
makespan
=
chromosome
.
getGenes
().
stream
()
.
mapToInt
(
Gene:
:
getEndTime
)
.
max
()
.
orElse
(
0
);
// 2. 总延迟时间
double
tardiness
=
0.0
;
Map
<
Integer
,
List
<
Gene
>>
orderGroups
=
chromosome
.
getGenes
().
stream
()
.
collect
(
Collectors
.
groupingBy
(
Gene:
:
getOrderId
));
for
(
Map
.
Entry
<
Integer
,
List
<
Gene
>>
group
:
orderGroups
.
entrySet
())
{
int
orderCompletion
=
group
.
getValue
().
stream
()
.
mapToInt
(
Gene:
:
getEndTime
)
.
max
()
.
orElse
(
0
);
Order
order
=
_orders
.
stream
()
.
filter
(
o
->
o
.
getId
()
==
group
.
getKey
())
.
findFirst
()
.
orElse
(
null
);
if
(
order
!=
null
)
{
LocalDateTime
completionTime
=
chromosome
.
getBaseTime
().
plusMinutes
(
orderCompletion
);
LocalDateTime
dueDateTime
=
order
.
getDueDate
().
toLocalDateTime
();
if
(
completionTime
.
isAfter
(
dueDateTime
))
{
long
hours
=
ChronoUnit
.
HOURS
.
between
(
dueDateTime
,
completionTime
);
long
minutes
=
ChronoUnit
.
MINUTES
.
between
(
dueDateTime
,
completionTime
)
%
60
;
tardiness
+=
hours
+
(
double
)
minutes
/
60
;
}
}
}
// 3. 总换型时间
double
totalSetupTime
=
CalculateTotalSetupTime
(
chromosome
);
// 4. 总流程时间
double
totalFlowTime
=
CalculateTotalFlowTime
(
chromosome
);
// 5. 机器负载均衡
double
machineLoadBalance
=
CalculateMachineLoadBalance
(
chromosome
);
// 存储目标值
HashMap
<
Integer
,
Double
>
objMap
=
new
HashMap
<>();
objMap
.
put
(
0
,
makespan
);
objMap
.
put
(
1
,
tardiness
);
objMap
.
put
(
2
,
totalSetupTime
);
objMap
.
put
(
3
,
totalFlowTime
);
objMap
.
put
(
4
,
machineLoadBalance
);
chromosome
.
setObjectiveValues
(
objMap
);
// 计算适应度
chromosome
.
setFitness
(
0.4
*
(
1.0
/
(
1
+
makespan
))
+
0.3
*
(
1.0
/
(
1
+
tardiness
))
+
0.1
*
(
1.0
/
(
1
+
totalSetupTime
))
+
0.1
*
(
1.0
/
(
1
+
totalFlowTime
))
+
0.1
*
machineLoadBalance
);
}
private
double
CalculateTotalSetupTime
(
ScheduleChromosome
chromosome
)
{
double
totalSetupTime
=
0.0
;
Map
<
Long
,
List
<
Gene
>>
machineGroups
=
chromosome
.
getGenes
().
stream
()
.
collect
(
Collectors
.
groupingBy
(
Gene:
:
getMachineId
));
for
(
Map
.
Entry
<
Long
,
List
<
Gene
>>
machineGroup
:
machineGroups
.
entrySet
())
{
List
<
Gene
>
sortedGenes
=
machineGroup
.
getValue
().
stream
()
.
sorted
(
Comparator
.
comparingInt
(
Gene:
:
getStartTime
))
.
collect
(
Collectors
.
toList
());
Integer
lastProductId
=
null
;
for
(
Gene
gene
:
sortedGenes
)
{
if
(
lastProductId
!=
null
&&
lastProductId
!=
gene
.
getProductId
())
{
Product
product
=
_products
.
stream
()
.
filter
(
p
->
p
.
getId
()
==
gene
.
getProductId
())
.
findFirst
()
.
orElse
(
null
);
if
(
product
==
null
)
continue
;
Operation
operation
=
product
.
getOperations
().
stream
()
.
filter
(
o
->
o
.
getId
()
==
gene
.
getOperationId
())
.
findFirst
()
.
orElse
(
null
);
if
(
operation
==
null
)
continue
;
MachineOption
machineOption
=
operation
.
getMachineOptions
().
stream
()
.
filter
(
m
->
m
.
getMachineId
()
==
gene
.
getMachineId
())
.
findFirst
()
.
orElse
(
null
);
if
(
machineOption
!=
null
)
{
totalSetupTime
+=
machineOption
.
getSetupTime
();
}
}
lastProductId
=
gene
.
getProductId
();
}
}
return
totalSetupTime
;
}
private
double
CalculateTotalFlowTime
(
ScheduleChromosome
chromosome
)
{
double
totalFlowTime
=
0.0
;
Map
<
Integer
,
List
<
Gene
>>
orderGroups
=
chromosome
.
getGenes
().
stream
()
.
collect
(
Collectors
.
groupingBy
(
Gene:
:
getOrderId
));
for
(
Map
.
Entry
<
Integer
,
List
<
Gene
>>
group
:
orderGroups
.
entrySet
())
{
int
minStartTime
=
group
.
getValue
().
stream
().
mapToInt
(
Gene:
:
getStartTime
).
min
().
orElse
(
0
);
int
maxEndTime
=
group
.
getValue
().
stream
().
mapToInt
(
Gene:
:
getEndTime
).
max
().
orElse
(
0
);
LocalDateTime
start
=
chromosome
.
getBaseTime
().
plusMinutes
(
minStartTime
);
LocalDateTime
end
=
chromosome
.
getBaseTime
().
plusMinutes
(
maxEndTime
);
long
hours
=
ChronoUnit
.
HOURS
.
between
(
start
,
end
);
long
minutes
=
ChronoUnit
.
MINUTES
.
between
(
start
,
end
)
%
60
;
totalFlowTime
+=
hours
+
(
double
)
minutes
/
60
;
}
return
totalFlowTime
;
}
private
double
CalculateMachineLoadBalance
(
ScheduleChromosome
chromosome
)
{
Map
<
Integer
,
Double
>
machineUtilization
=
new
HashMap
<>();
int
maxEndTime
=
chromosome
.
getGenes
().
stream
()
.
mapToInt
(
Gene:
:
getEndTime
)
.
max
()
.
orElse
(
0
);
if
(
maxEndTime
==
0
)
return
0.0
;
for
(
Machine
machine
:
_machines
)
{
double
busyTime
=
chromosome
.
getGenes
().
stream
()
.
filter
(
g
->
g
.
getMachineId
()
==
machine
.
getId
())
.
mapToInt
(
g
->
g
.
getEndTime
()
-
g
.
getStartTime
())
.
sum
();
machineUtilization
.
put
((
int
)
machine
.
getId
(),
busyTime
/
maxEndTime
);
}
double
avgUtilization
=
machineUtilization
.
values
().
stream
().
mapToDouble
(
Double:
:
doubleValue
).
average
().
orElse
(
0.0
);
double
variance
=
machineUtilization
.
values
().
stream
()
.
mapToDouble
(
u
->
Math
.
pow
(
u
-
avgUtilization
,
2
))
.
average
()
.
orElse
(
0.0
);
return
1.0
/
(
1
+
variance
);
}
private
int
calculateSetupTime
(
List
<
Gene
>
existingGenes
,
Order
currentOrder
,
Machine
machine
,
MachineOption
machineOption
)
{
Gene
lastGeneOnMachine
=
existingGenes
.
stream
()
.
filter
(
g
->
g
.
getMachineId
()
==
machine
.
getId
())
.
max
(
Comparator
.
comparingInt
(
Gene:
:
getEndTime
))
.
orElse
(
null
);
if
(
lastGeneOnMachine
==
null
)
{
System
.
out
.
println
(
"设备 "
+
machine
.
getId
()
+
" 上无历史任务,换型时间为0"
);
return
0
;
}
int
setupTime
=
(
lastGeneOnMachine
.
getProductId
()
!=
currentOrder
.
getProductId
())
?
machineOption
.
getSetupTime
()
:
0
;
if
(
setupTime
>
0
)
{
System
.
out
.
println
(
"设备 "
+
machine
.
getId
()
+
" 需要换型,因为产品从 "
+
lastGeneOnMachine
.
getProductId
()
+
" 变更为 "
+
currentOrder
.
getProductId
());
}
return
setupTime
;
}
/**
* 计算主处理开始时间,确保在工作时间内
*/
/**
* 计算主处理开始时间,基于设备日历确保在工作时间内
*/
/**
* 计算主处理开始时间,基于设备日历确保在工作时间内
*/
/**
* 计算主处理开始时间
*/
private
int
calculateMainProcessingStartTime
(
Machine
machine
,
int
setupStartTime
,
int
absoluteSetupTime
,
List
<
GeneDetail
>
geneDetails
)
{
System
.
out
.
println
(
" 计算主处理开始时间:"
);
System
.
out
.
println
(
" 换型开始时间: "
+
ConvertTime
(
setupStartTime
)
+
" ("
+
baseTime
.
plusMinutes
(
setupStartTime
)
+
")"
);
System
.
out
.
println
(
" 绝对换型时长: "
+
absoluteSetupTime
+
"分钟 ("
+
(
absoluteSetupTime
/
60.0
)
+
"小时)"
);
// 主处理开始时间 = 换型开始时间 + 绝对换型时长
int
mainProcessingStartTime
=
setupStartTime
+
absoluteSetupTime
;
System
.
out
.
println
(
" 计算主处理开始时间: "
+
ConvertTime
(
mainProcessingStartTime
)
+
" ("
+
baseTime
.
plusMinutes
(
mainProcessingStartTime
)
+
")"
);
return
mainProcessingStartTime
;
}
/**
* 调整时间到设备的下一个可用工作时间
*/
private
int
adjustToMachineWorkingTime
(
Machine
machine
,
int
minute
)
{
LocalDateTime
time
=
baseTime
.
plusMinutes
(
minute
);
System
.
out
.
println
(
" 调整时间到工作时间: "
+
ConvertTime
(
minute
));
// 查找包含或最接近给定时间的可用时间段
for
(
TimeSegment
segment
:
machine
.
getAvailability
())
{
if
(
segment
.
getType
()
!=
SegmentType
.
MAINTENANCE
&&
!
segment
.
isUsed
())
{
LocalDateTime
segmentStart
=
segment
.
getStart
();
LocalDateTime
segmentEnd
=
segment
.
getEnd
();
// 如果时间在时间段内,直接返回
if
((
time
.
isAfter
(
segmentStart
)
||
time
.
equals
(
segmentStart
))
&&
time
.
isBefore
(
segmentEnd
))
{
System
.
out
.
println
(
" 时间 "
+
ConvertTime
(
minute
)
+
" 在工作时间内,无需调整"
);
return
minute
;
}
// 如果时间在时间段之前,返回时间段的开始时间
if
(
time
.
isBefore
(
segmentStart
))
{
int
adjustedMinute
=
(
int
)
ChronoUnit
.
MINUTES
.
between
(
baseTime
,
segmentStart
);
System
.
out
.
println
(
" 时间 "
+
ConvertTime
(
minute
)
+
" 在工作时间前,调整到 "
+
ConvertTime
(
adjustedMinute
));
return
adjustedMinute
;
}
}
}
// 如果没有找到合适的时间段,生成新的时间段
System
.
out
.
println
(
" 未找到合适的工作时间段,生成新时间段"
);
List
<
TimeSegment
>
timeSegments
=
_machineScheduler
.
generateTimeSegment
(
machine
,
time
);
machine
.
getAvailability
().
addAll
(
timeSegments
);
// 查找新生成的时间段
for
(
TimeSegment
segment
:
timeSegments
)
{
if
(
segment
.
getType
()
!=
SegmentType
.
MAINTENANCE
&&
!
segment
.
isUsed
())
{
LocalDateTime
segmentStart
=
segment
.
getStart
();
int
adjustedMinute
=
(
int
)
ChronoUnit
.
MINUTES
.
between
(
baseTime
,
segmentStart
);
System
.
out
.
println
(
" 生成新时间段,调整到 "
+
ConvertTime
(
adjustedMinute
));
return
adjustedMinute
;
}
}
// 如果仍然没有找到,返回原时间
System
.
out
.
println
(
" ⚠️ 无法找到合适的工作时间,使用原时间"
);
return
minute
;
}
/**
* 计算绝对换型时间(仅用于标准模式)
* 绝对换型时间 = 计划换型时间 + 非工作时间间隔
*/
/**
* 计算绝对换型时间(仅用于标准模式)
* 绝对换型时间 = 计划换型时间 + 非工作时间间隔
* @return 绝对换型时长(分钟)
*/
/**
* 计算绝对换型时间(仅用于标准模式)
* 绝对换型时间 = 计划换型时间 + 非工作时间间隔
* @return 绝对换型时长(分钟)
*/
/**
* 计算绝对换型时间(仅用于标准模式)
* 绝对换型时间 = 计划换型时间 + 非工作时间间隔
* @return 绝对换型时长(分钟)
*/
private
int
calculateAbsoluteSetupTime
(
Gene
gene
,
Machine
machine
)
{
if
(
gene
.
getGeneDetails
()
==
null
||
gene
.
getGeneDetails
().
isEmpty
())
{
System
.
out
.
println
(
" 计算绝对换型时间: 无时间段详情,使用计划时间 "
+
gene
.
getSetupTime
()
+
"分钟"
);
return
gene
.
getSetupTime
();
}
// 按开始时间排序时间段
List
<
GeneDetail
>
sortedDetails
=
gene
.
getGeneDetails
().
stream
()
.
sorted
(
Comparator
.
comparingInt
(
GeneDetail:
:
getStartTime
))
.
collect
(
Collectors
.
toList
());
int
remainingSetupTime
=
gene
.
getSetupTime
();
int
accumulatedAbsoluteTime
=
0
;
int
currentTime
=
gene
.
getStartTime
();
// 当前时间,从换型开始时间开始
System
.
out
.
println
(
" 计算绝对换型时间:"
);
System
.
out
.
println
(
" 开始时间: "
+
ConvertTime
(
currentTime
)
+
" ("
+
baseTime
.
plusMinutes
(
currentTime
)
+
")"
);
System
.
out
.
println
(
" 计划换型时间: "
+
remainingSetupTime
+
"分钟"
);
// 遍历时间段,分配换型时间
for
(
GeneDetail
detail
:
sortedDetails
)
{
int
segmentStart
=
detail
.
getStartTime
();
int
segmentEnd
=
detail
.
getEndTime
();
int
segmentDuration
=
segmentEnd
-
segmentStart
;
System
.
out
.
println
(
" 处理时间段: "
+
ConvertTime
(
segmentStart
)
+
" - "
+
ConvertTime
(
segmentEnd
)
+
" ("
+
segmentDuration
+
"分钟)"
);
// 如果当前时间在时间段之前,需要等待到时间段开始
if
(
currentTime
<
segmentStart
)
{
int
waitTime
=
segmentStart
-
currentTime
;
accumulatedAbsoluteTime
+=
waitTime
;
System
.
out
.
println
(
" 等待时间段开始: "
+
waitTime
+
"分钟 ("
+
ConvertTime
(
currentTime
)
+
" → "
+
ConvertTime
(
segmentStart
)
+
")"
);
currentTime
=
segmentStart
;
}
// 如果当前时间在时间段内
if
(
currentTime
>=
segmentStart
&&
currentTime
<
segmentEnd
)
{
int
availableTimeInSegment
=
segmentEnd
-
currentTime
;
System
.
out
.
println
(
" 时间段内可用时间: "
+
availableTimeInSegment
+
"分钟"
);
if
(
availableTimeInSegment
>=
remainingSetupTime
)
{
// 当前时间段可以完成剩余换型
accumulatedAbsoluteTime
+=
remainingSetupTime
;
currentTime
+=
remainingSetupTime
;
remainingSetupTime
=
0
;
System
.
out
.
println
(
" 换型完成于: "
+
ConvertTime
(
currentTime
));
break
;
}
else
{
// 使用整个时间段的剩余时间
accumulatedAbsoluteTime
+=
availableTimeInSegment
;
remainingSetupTime
-=
availableTimeInSegment
;
currentTime
=
segmentEnd
;
System
.
out
.
println
(
" 使用时间段剩余时间: "
+
availableTimeInSegment
+
"分钟"
);
System
.
out
.
println
(
" 剩余换型时间: "
+
remainingSetupTime
+
"分钟"
);
}
}
}
// 如果换型未完成,使用计划时间
if
(
remainingSetupTime
>
0
)
{
System
.
out
.
println
(
" 换型未完成,剩余时间: "
+
remainingSetupTime
+
"分钟,使用计划时间"
);
accumulatedAbsoluteTime
+=
remainingSetupTime
;
}
System
.
out
.
println
(
" 最终绝对换型时长: "
+
accumulatedAbsoluteTime
+
"分钟 ("
+
(
accumulatedAbsoluteTime
/
60.0
)
+
"小时)"
);
System
.
out
.
println
(
" 非工作时间间隔: "
+
(
accumulatedAbsoluteTime
-
gene
.
getSetupTime
())
+
"分钟"
);
return
accumulatedAbsoluteTime
;
}
private
int
calculateSetupTimeForConflict
(
List
<
Gene
>
existingGenes
,
Order
currentOrder
,
Machine
machine
,
MachineOption
machineOption
,
Gene
conflictingGene
)
{
int
setupTime
=
(
conflictingGene
.
getProductId
()
!=
currentOrder
.
getProductId
())
?
machineOption
.
getSetupTime
()
:
0
;
if
(
existingGenes
.
stream
().
filter
(
g
->
g
.
getMachineId
()
==
machine
.
getId
()).
count
()
<=
1
)
{
setupTime
=
0
;
}
if
(
setupTime
>
0
)
{
System
.
out
.
println
(
"设备 "
+
machine
.
getId
()
+
" 需要换型,因为产品从 "
+
conflictingGene
.
getProductId
()
+
" 变更为 "
+
currentOrder
.
getProductId
());
}
return
setupTime
;
}
private
List
<
GeneDetail
>
GetNextAvailableTime
(
Machine
machine
,
int
proposedStartTime
,
int
prevtime
,
int
processingTime
,
List
<
Gene
>
existingTasks
,
boolean
IsInterrupt
,
boolean
istask
)
{
LocalDateTime
startTime
=
baseTime
.
plusMinutes
(
proposedStartTime
);
String
prevtimeStr
=
prevtime
>
-
1
?
baseTime
.
plusMinutes
(
prevtime
).
toString
()
:
""
;
return
FindEarliestStart
(
machine
,
processingTime
,
startTime
,
prevtimeStr
,
existingTasks
,
istask
);
}
private
List
<
GeneDetail
>
FindEarliestStart
(
Machine
machine
,
int
processingTime
,
LocalDateTime
currentTime
,
String
prevtime
,
List
<
Gene
>
existingTasks
,
boolean
checkprevtime
)
{
List
<
Gene
>
machineTasks
=
existingTasks
.
stream
()
.
filter
(
t
->
t
.
getMachineId
()
==
machine
.
getId
())
.
sorted
(
Comparator
.
comparingInt
(
Gene:
:
getStartTime
))
.
collect
(
Collectors
.
toList
());
List
<
GeneDetail
>
times
=
new
ArrayList
<>();
TimeSegment
slot
=
GetCurrentOrNextShift
(
machine
,
currentTime
,
prevtime
,
checkprevtime
);
if
(
slot
==
null
)
return
times
;
LocalDateTime
prevTimeDateTime
=
StringUtils
.
isEmpty
(
prevtime
)
?
null
:
LocalDateTime
.
parse
(
prevtime
);
LocalDateTime
startCandidate
=
slot
.
getStart
().
isAfter
(
prevTimeDateTime
!=
null
?
prevTimeDateTime
:
currentTime
)
?
slot
.
getStart
()
:
(
prevTimeDateTime
!=
null
?
prevTimeDateTime
:
currentTime
);
LocalDateTime
endCandidate
=
startCandidate
.
plusMinutes
(
processingTime
);
if
(
endCandidate
.
isAfter
(
slot
.
getEnd
()))
{
return
CaldEarliestStart
(
machine
,
processingTime
,
currentTime
,
prevtime
,
machineTasks
,
checkprevtime
);
}
else
{
GeneDetail
time
=
new
GeneDetail
();
time
.
setKey
(
slot
.
getKey
());
time
.
setStartTime
((
int
)
ChronoUnit
.
MINUTES
.
between
(
baseTime
,
startCandidate
));
time
.
setEndTime
((
int
)
ChronoUnit
.
MINUTES
.
between
(
baseTime
,
endCandidate
));
times
.
add
(
time
);
RemoveMachineAvailable
(
machine
,
time
);
return
times
;
}
}
private
List
<
GeneDetail
>
CaldEarliestStart
(
Machine
machine
,
int
processingTime
,
LocalDateTime
currentTime
,
String
prevtime
,
List
<
Gene
>
machineTasks
,
boolean
checkprevtime
)
{
int
remainingTime
=
processingTime
;
LocalDateTime
st
=
StringUtils
.
isEmpty
(
prevtime
)
?
currentTime
:
LocalDateTime
.
parse
(
prevtime
);
LocalDateTime
prevEnd
=
LocalDateTime
.
of
(
2000
,
1
,
1
,
0
,
0
,
0
);
List
<
GeneDetail
>
times
=
new
ArrayList
<>();
List
<
GeneDetail
>
oldTimes
=
new
ArrayList
<>();
while
(
remainingTime
>
0
)
{
TimeSegment
shift
=
GetCurrentOrNextShift
(
machine
,
currentTime
,
prevtime
,
checkprevtime
);
if
(
shift
==
null
)
break
;
LocalDateTime
shiftStart
=
shift
.
getStart
();
LocalDateTime
shiftEnd
=
shift
.
getEnd
();
// 检查班次间冲突
if
(!
prevEnd
.
isEqual
(
LocalDateTime
.
of
(
2000
,
1
,
1
,
0
,
0
,
0
)))
{
if
(
prevEnd
.
isBefore
(
currentTime
))
{
// 检查班次间任务
LocalDateTime
finalPrevEnd
=
prevEnd
;
boolean
hasTask
=
machineTasks
.
stream
()
.
anyMatch
(
t
->
{
LocalDateTime
taskStart
=
baseTime
.
plusMinutes
(
t
.
getStartTime
());
return
taskStart
.
isAfter
(
finalPrevEnd
)
&&
taskStart
.
isBefore
(
shiftStart
);
});
if
(
hasTask
)
{
// 重置状态
currentTime
=
shiftStart
;
st
=
shiftStart
;
remainingTime
=
processingTime
;
prevEnd
=
LocalDateTime
.
of
(
2000
,
1
,
1
,
0
,
0
,
0
);
oldTimes
.
addAll
(
deepCopyGeneDetailList
(
times
));
times
.
clear
();
continue
;
}
// 检查班次间维修窗口
if
(
machine
.
getMaintenanceWindows
()
!=
null
)
{
LocalDateTime
finalPrevEnd1
=
prevEnd
;
boolean
hasMaintenance
=
machine
.
getMaintenanceWindows
().
stream
()
.
anyMatch
(
w
->
w
.
getStartTime
().
isAfter
(
finalPrevEnd1
)
&&
w
.
getStartTime
().
isBefore
(
shiftStart
));
if
(
hasMaintenance
)
{
currentTime
=
shiftStart
;
st
=
shiftStart
;
remainingTime
=
processingTime
;
prevEnd
=
LocalDateTime
.
of
(
2000
,
1
,
1
,
0
,
0
,
0
);
times
.
clear
();
continue
;
}
}
}
}
prevEnd
=
shiftEnd
;
// 计算有效时间
LocalDateTime
effectiveStart
=
st
.
isAfter
(
shiftStart
)
?
st
:
shiftStart
;
long
availableMinutes
=
ChronoUnit
.
MINUTES
.
between
(
effectiveStart
,
shiftEnd
);
// 处理当前班次
int
processable
=
Math
.
min
(
remainingTime
,
(
int
)
availableMinutes
);
remainingTime
-=
processable
;
currentTime
=
effectiveStart
.
plusMinutes
(
processable
);
// 添加时间详情
GeneDetail
time
=
new
GeneDetail
();
time
.
setKey
(
shift
.
getKey
());
time
.
setStartTime
((
int
)
ChronoUnit
.
MINUTES
.
between
(
baseTime
,
effectiveStart
));
time
.
setEndTime
((
int
)
ChronoUnit
.
MINUTES
.
between
(
baseTime
,
currentTime
));
times
.
add
(
time
);
RemoveMachineAvailable
(
machine
,
time
);
}
// 还原未使用的时间段
AddMachineAvailable
(
machine
,
oldTimes
);
return
times
;
}
private
TimeSegment
GetCurrentOrNextShift
(
Machine
machine
,
LocalDateTime
time
,
String
prevtime
,
boolean
checkprevtime
)
{
TimeSegment
start
=
null
;
// 查找有效班次
start
=
machine
.
getAvailability
().
stream
()
.
filter
(
slot
->
!
slot
.
isUsed
()
&&
slot
.
getType
()
!=
SegmentType
.
MAINTENANCE
)
.
filter
(
slot
->
slot
.
getStart
().
isAfter
(
time
)
||
slot
.
getEnd
().
isAfter
(
time
))
.
findFirst
()
.
orElse
(
null
);
if
(
start
==
null
)
{
// 生成新时间段
List
<
TimeSegment
>
timeSegments
=
_machineScheduler
.
generateTimeSegment
(
machine
,
time
);
machine
.
getAvailability
().
addAll
(
timeSegments
);
// 更新设备时间线
Machine
originalMachine
=
_machines
.
stream
()
.
filter
(
t
->
t
.
getId
()
==
machine
.
getId
())
.
findFirst
()
.
orElse
(
null
);
if
(
originalMachine
!=
null
)
{
MachineTimeline
timeline
=
_machineScheduler
.
getOrCreateTimeline
(
originalMachine
);
}
// 递归查找
return
GetCurrentOrNextShift
(
machine
,
time
,
prevtime
,
checkprevtime
);
}
return
start
;
}
private
void
RemoveMachineAvailable
(
Machine
machine
,
GeneDetail
geneDetails
)
{
List
<
TimeSegment
>
timeSegments
=
new
ArrayList
<>();
// 查找对应时间段
int
index
=
machine
.
getAvailability
().
stream
()
.
filter
(
t
->
t
.
getKey
().
equals
(
geneDetails
.
getKey
()))
.
findFirst
()
.
map
(
machine
.
getAvailability
()::
indexOf
)
.
orElse
(-
1
);
if
(
index
>
-
1
)
{
TimeSegment
targetSegment
=
machine
.
getAvailability
().
get
(
index
);
LocalDateTime
geneEndTime
=
baseTime
.
plusMinutes
(
geneDetails
.
getEndTime
());
if
(
targetSegment
.
getEnd
().
isAfter
(
geneEndTime
))
{
// 拆分时间段
TimeSegment
usedSegment
=
new
TimeSegment
();
usedSegment
.
setStart
(
baseTime
.
plusMinutes
(
geneDetails
.
getStartTime
()));
usedSegment
.
setEnd
(
geneEndTime
);
usedSegment
.
setHoliday
(
false
);
usedSegment
.
setKey
(
UUID
.
randomUUID
().
toString
());
usedSegment
.
setType
(
SegmentType
.
REGULAR
);
usedSegment
.
setUsed
(
true
);
timeSegments
.
add
(
usedSegment
);
// 更新基因详情Key
geneDetails
.
setKey
(
usedSegment
.
getKey
());
// 更新原时间段开始时间
targetSegment
.
setStart
(
geneEndTime
);
}
else
{
targetSegment
.
setUsed
(
true
);
}
}
// 添加新段并排序
if
(!
timeSegments
.
isEmpty
())
{
machine
.
getAvailability
().
addAll
(
timeSegments
);
}
machine
.
getAvailability
().
sort
(
Comparator
.
comparing
(
TimeSegment:
:
getStart
));
}
private
void
AddMachineAvailable
(
Machine
machine
,
List
<
GeneDetail
>
geneDetails
)
{
if
(
geneDetails
==
null
||
geneDetails
.
isEmpty
())
return
;
// 标记时间段为未占用
for
(
GeneDetail
detail
:
geneDetails
)
{
machine
.
getAvailability
().
stream
()
.
filter
(
t
->
t
.
getKey
().
equals
(
detail
.
getKey
()))
.
findFirst
()
.
ifPresent
(
t
->
t
.
setUsed
(
false
));
}
// 合并时间段
machine
.
setAvailability
(
MergeSegments
(
machine
.
getAvailability
()));
}
private
List
<
TimeSegment
>
MergeSegments
(
List
<
TimeSegment
>
segments
)
{
// 分离维护段、未占用段、已占用段
List
<
TimeSegment
>
maintenanceSegments
=
segments
.
stream
()
.
filter
(
t
->
t
.
getType
()
==
SegmentType
.
MAINTENANCE
)
.
collect
(
Collectors
.
toList
());
List
<
TimeSegment
>
unusedRegularSegments
=
segments
.
stream
()
.
filter
(
t
->
t
.
getType
()
!=
SegmentType
.
MAINTENANCE
&&
!
t
.
isUsed
())
.
collect
(
Collectors
.
toList
());
List
<
TimeSegment
>
usedRegularSegments
=
segments
.
stream
()
.
filter
(
t
->
t
.
getType
()
!=
SegmentType
.
MAINTENANCE
&&
t
.
isUsed
())
.
collect
(
Collectors
.
toList
());
// 排序未占用段
unusedRegularSegments
.
sort
(
Comparator
.
comparing
(
TimeSegment:
:
getStart
));
// 合并未占用段
Deque
<
TimeSegment
>
mergedUnused
=
new
ArrayDeque
<>();
for
(
TimeSegment
seg
:
unusedRegularSegments
)
{
if
(!
mergedUnused
.
isEmpty
()
&&
mergedUnused
.
peekLast
().
getEnd
().
isAfter
(
seg
.
getStart
()))
{
TimeSegment
last
=
mergedUnused
.
pollLast
();
last
.
setEnd
(
last
.
getEnd
().
isAfter
(
seg
.
getEnd
())
?
last
.
getEnd
()
:
seg
.
getEnd
());
mergedUnused
.
offerLast
(
last
);
}
else
{
mergedUnused
.
offerLast
(
seg
);
}
}
// 重组结果
List
<
TimeSegment
>
result
=
new
ArrayList
<>(
mergedUnused
);
result
.
addAll
(
usedRegularSegments
);
result
.
addAll
(
maintenanceSegments
);
result
.
sort
(
Comparator
.
comparing
(
TimeSegment:
:
getStart
));
return
result
;
}
public
void
PrintScheduleSummary
(
ScheduleChromosome
schedule
)
{
System
.
out
.
println
(
"\n=== Schedule Summary ==="
);
// 按订单分组打印
Map
<
Integer
,
List
<
Gene
>>
orderGroups
=
schedule
.
getGenes
().
stream
()
.
collect
(
Collectors
.
groupingBy
(
Gene:
:
getOrderId
));
for
(
Map
.
Entry
<
Integer
,
List
<
Gene
>>
group
:
orderGroups
.
entrySet
())
{
System
.
out
.
printf
(
"\nOrder %d Schedule:%n"
,
group
.
getKey
());
// 按工序排序
List
<
Gene
>
sortedJobs
=
group
.
getValue
().
stream
()
.
sorted
(
Comparator
.
comparingInt
(
Gene:
:
getOperationId
))
.
collect
(
Collectors
.
toList
());
for
(
Gene
job
:
sortedJobs
)
{
Product
product
=
_products
.
stream
()
.
filter
(
p
->
p
.
getId
()
==
job
.
getProductId
())
.
findFirst
()
.
orElse
(
null
);
Operation
operation
=
product
!=
null
?
product
.
getOperations
().
stream
()
.
filter
(
o
->
o
.
getId
()
==
job
.
getOperationId
())
.
findFirst
()
.
orElse
(
null
)
:
null
;
if
(
product
!=
null
&&
operation
!=
null
)
{
String
print
=
String
.
format
(
"[%s-%s] Order %d, Product %s, Machine %d, Operation %d, Batch %d, processingTime %d, setupTime %d, teardownTime %d"
,
ConvertTime
(
job
.
getStartTime
()),
ConvertTime
(
job
.
getEndTime
()),
job
.
getOrderId
(),
product
.
getName
(),
job
.
getMachineId
(),
operation
.
getSequence
(),
job
.
getBatchSize
(),
job
.
getProcessingTime
(),
job
.
getSetupTime
(),
job
.
getTeardownTime
()
);
System
.
out
.
println
(
print
);
}
}
}
}
public
void
WriteScheduleSummary
(
ScheduleChromosome
schedule
)
{
// 写入日志
FileHelper
.
writeLogFile
(
String
.
format
(
"\n=== Schedule Summary === %f"
,
schedule
.
getFitness
()));
FileHelper
.
writeLogFile
(
String
.
format
(
"Makespan: %f minutes"
,
schedule
.
getObjectiveValues
().
get
(
0
)));
FileHelper
.
writeLogFile
(
String
.
format
(
"Total Tardiness: %f hours"
,
schedule
.
getObjectiveValues
().
get
(
1
)));
FileHelper
.
writeLogFile
(
String
.
format
(
"Setup Time: %f minutes"
,
schedule
.
getObjectiveValues
().
get
(
2
)));
FileHelper
.
writeLogFile
(
String
.
format
(
"Flow Time: %f minutes"
,
schedule
.
getObjectiveValues
().
get
(
3
)));
FileHelper
.
writeLogFile
(
String
.
format
(
"Machine Load Balance: %.2f%%"
,
schedule
.
getObjectiveValues
().
get
(
4
)
*
100
));
System
.
out
.
println
(
schedule
.
getSceneId
());
FileHelper
.
writeLogFile
(
"-------------------------"
);
// 按订单分组写入
Map
<
Integer
,
List
<
Gene
>>
orderGroups
=
schedule
.
getGenes
().
stream
()
.
collect
(
Collectors
.
groupingBy
(
Gene:
:
getOrderId
));
for
(
Map
.
Entry
<
Integer
,
List
<
Gene
>>
group
:
orderGroups
.
entrySet
())
{
List
<
Gene
>
sortedJobs
=
group
.
getValue
().
stream
()
.
sorted
(
Comparator
.
comparingInt
(
Gene:
:
getOperationId
))
.
collect
(
Collectors
.
toList
());
for
(
Gene
job
:
sortedJobs
)
{
Product
product
=
_products
.
stream
()
.
filter
(
p
->
p
.
getId
()
==
job
.
getProductId
())
.
findFirst
()
.
orElse
(
null
);
Operation
operation
=
product
!=
null
?
product
.
getOperations
().
stream
()
.
filter
(
o
->
o
.
getId
()
==
job
.
getOperationId
())
.
findFirst
()
.
orElse
(
null
)
:
null
;
if
(
product
!=
null
&&
operation
!=
null
)
{
StringBuilder
sb
=
new
StringBuilder
();
sb
.
append
(
String
.
format
(
"[%d-%d]:[%s-%s] Order %d, Product %s, Machine %d, Operation %d, Batch %d, processingTime %d, setupTime %d, teardownTime %d"
,
job
.
getStartTime
(),
job
.
getEndTime
(),
ConvertTime
(
job
.
getStartTime
()),
ConvertTime
(
job
.
getEndTime
()),
job
.
getOrderId
(),
product
.
getName
(),
job
.
getMachineId
(),
operation
.
getSequence
(),
job
.
getBatchSize
(),
job
.
getProcessingTime
(),
job
.
getSetupTime
(),
job
.
getTeardownTime
()
));
// 追加基因详情
for
(
GeneDetail
d
:
job
.
getGeneDetails
())
{
sb
.
append
(
String
.
format
(
"\n\t\t\t\t\t\t\t\t\t\t [%d-%d]:[%s-%s] %d"
,
d
.
getStartTime
(),
d
.
getEndTime
(),
ConvertTime
(
d
.
getStartTime
()),
ConvertTime
(
d
.
getEndTime
()),
d
.
getEndTime
()
-
d
.
getStartTime
()
));
}
FileHelper
.
writeLogFile
(
sb
.
toString
());
}
}
FileHelper
.
writeLogFile
(
""
);
}
}
private
String
ConvertTime
(
int
minute
)
{
return
baseTime
.
plusMinutes
(
minute
).
format
(
java
.
time
.
format
.
DateTimeFormatter
.
ofPattern
(
"MM-dd HH:mm"
));
}
// ========================== 深拷贝工具方法 ==========================
private
List
<
Product
>
deepCopyProductList
(
List
<
Product
>
source
)
{
return
source
==
null
?
new
ArrayList
<>()
:
source
.
stream
().
map
(
this
::
deepCopyProduct
).
collect
(
Collectors
.
toList
());
}
private
Product
deepCopyProduct
(
Product
source
)
{
if
(
source
==
null
)
return
null
;
Product
copy
=
new
Product
();
copy
.
setId
(
source
.
getId
());
copy
.
setName
(
source
.
getName
());
copy
.
setOperations
(
deepCopyOperationList
(
source
.
getOperations
()));
return
copy
;
}
private
List
<
Operation
>
deepCopyOperationList
(
List
<
Operation
>
source
)
{
return
source
==
null
?
new
ArrayList
<>()
:
source
.
stream
().
map
(
this
::
deepCopyOperation
).
collect
(
Collectors
.
toList
());
}
private
Operation
deepCopyOperation
(
Operation
source
)
{
if
(
source
==
null
)
return
null
;
Operation
copy
=
new
Operation
();
copy
.
setId
(
source
.
getId
());
copy
.
setProductId
(
source
.
getProductId
());
copy
.
setSequence
(
source
.
getSequence
());
copy
.
setInterrupt
(
source
.
isInterrupt
());
copy
.
setMachineOptions
(
deepCopyMachineOptionList
(
source
.
getMachineOptions
()));
return
copy
;
}
private
List
<
MachineOption
>
deepCopyMachineOptionList
(
List
<
MachineOption
>
source
)
{
return
source
==
null
?
new
ArrayList
<>()
:
source
.
stream
().
map
(
this
::
deepCopyMachineOption
).
collect
(
Collectors
.
toList
());
}
private
MachineOption
deepCopyMachineOption
(
MachineOption
source
)
{
if
(
source
==
null
)
return
null
;
MachineOption
copy
=
new
MachineOption
();
copy
.
setMachineId
(
source
.
getMachineId
());
copy
.
setProcessingTime
(
source
.
getProcessingTime
());
copy
.
setSetupTime
(
source
.
getSetupTime
());
copy
.
setTeardownTime
(
source
.
getTeardownTime
());
copy
.
setPreTime
(
source
.
getPreTime
());
return
copy
;
}
private
List
<
Machine
>
deepCopyMachineList
(
List
<
Machine
>
source
)
{
return
source
==
null
?
new
ArrayList
<>()
:
source
.
stream
().
map
(
this
::
deepCopyMachine
).
collect
(
Collectors
.
toList
());
}
private
Machine
deepCopyMachine
(
Machine
source
)
{
if
(
source
==
null
)
return
null
;
Machine
copy
=
new
Machine
();
copy
.
setId
(
source
.
getId
());
copy
.
setName
(
source
.
getName
());
copy
.
setEarliestTime
(
source
.
getEarliestTime
());
copy
.
setTotalTaskTime
(
source
.
getTotalTaskTime
());
copy
.
setShifts
(
deepCopyShiftList
(
source
.
getShifts
()));
copy
.
setMaintenanceWindows
(
deepCopyMaintenanceWindowList
(
source
.
getMaintenanceWindows
()));
copy
.
setAvailability
(
deepCopyTimeSegmentList
(
source
.
getAvailability
()));
copy
.
setShiftsChanged
(
source
.
getShiftsChanged
());
copy
.
setMaintenanceWindowsChanged
(
source
.
getMaintenanceWindowsChanged
());
return
copy
;
}
private
List
<
Shift
>
deepCopyShiftList
(
List
<
Shift
>
source
)
{
return
source
==
null
?
new
ArrayList
<>()
:
source
.
stream
().
map
(
this
::
deepCopyShift
).
collect
(
Collectors
.
toList
());
}
private
Shift
deepCopyShift
(
Shift
source
)
{
if
(
source
==
null
)
return
null
;
Shift
copy
=
new
Shift
();
copy
.
setStartTime
(
source
.
getStartTime
());
copy
.
setEndTime
(
source
.
getEndTime
());
copy
.
setDays
(
source
.
getDays
()
!=
null
?
new
HashSet
<>(
source
.
getDays
())
:
null
);
copy
.
setShiftDate
(
source
.
getShiftDate
());
copy
.
setTemporaryShift
(
source
.
isTemporaryShift
());
copy
.
setPriority
(
source
.
getPriority
());
return
copy
;
}
private
List
<
MaintenanceWindow
>
deepCopyMaintenanceWindowList
(
List
<
MaintenanceWindow
>
source
)
{
return
source
==
null
?
new
ArrayList
<>()
:
source
.
stream
().
map
(
this
::
deepCopyMaintenanceWindow
).
collect
(
Collectors
.
toList
());
}
private
MaintenanceWindow
deepCopyMaintenanceWindow
(
MaintenanceWindow
source
)
{
if
(
source
==
null
)
return
null
;
MaintenanceWindow
copy
=
new
MaintenanceWindow
();
copy
.
setStartTime
(
source
.
getStartTime
());
copy
.
setEndTime
(
source
.
getEndTime
());
copy
.
setReason
(
source
.
getReason
());
return
copy
;
}
private
List
<
TimeSegment
>
deepCopyTimeSegmentList
(
List
<
TimeSegment
>
source
)
{
return
source
==
null
?
new
ArrayList
<>()
:
source
.
stream
().
map
(
this
::
deepCopyTimeSegment
).
collect
(
Collectors
.
toList
());
}
private
TimeSegment
deepCopyTimeSegment
(
TimeSegment
source
)
{
if
(
source
==
null
)
return
null
;
TimeSegment
copy
=
new
TimeSegment
();
copy
.
setKey
(
source
.
getKey
());
copy
.
setStart
(
source
.
getStart
());
copy
.
setEnd
(
source
.
getEnd
());
copy
.
setEarliestTime
(
source
.
getEarliestTime
());
copy
.
setTotalTaskTime
(
source
.
getTotalTaskTime
());
copy
.
setType
(
source
.
getType
());
copy
.
setHoliday
(
source
.
isHoliday
());
copy
.
setUsed
(
source
.
isUsed
());
return
copy
;
}
private
List
<
Order
>
deepCopyOrderList
(
List
<
Order
>
source
)
{
return
source
==
null
?
new
ArrayList
<>()
:
source
.
stream
().
map
(
this
::
deepCopyOrder
).
collect
(
Collectors
.
toList
());
}
private
Order
deepCopyOrder
(
Order
source
)
{
if
(
source
==
null
)
return
null
;
Order
copy
=
new
Order
();
copy
.
setId
(
source
.
getId
());
copy
.
setProductId
(
source
.
getProductId
());
copy
.
setQuantity
(
source
.
getQuantity
());
copy
.
setDueDate
(
source
.
getDueDate
());
copy
.
setOrderCompletion
(
source
.
getOrderCompletion
());
copy
.
setTardiness
(
source
.
getTardiness
());
copy
.
setPriority
(
source
.
getPriority
());
copy
.
setCanSplit
(
source
.
isCanSplit
());
copy
.
setCanInterrupt
(
source
.
isCanInterrupt
());
return
copy
;
}
private
List
<
Gene
>
deepCopyGeneList
(
List
<
Gene
>
source
)
{
return
source
==
null
?
new
ArrayList
<>()
:
source
.
stream
().
map
(
this
::
deepCopyGene
).
collect
(
Collectors
.
toList
());
}
private
Gene
deepCopyGene
(
Gene
source
)
{
if
(
source
==
null
)
return
null
;
Gene
copy
=
new
Gene
();
copy
.
setOrderId
(
source
.
getOrderId
());
copy
.
setProductId
(
source
.
getProductId
());
copy
.
setOperationId
(
source
.
getOperationId
());
copy
.
setMachineId
(
source
.
getMachineId
());
copy
.
setBatchSize
(
source
.
getBatchSize
());
copy
.
setStartTime
(
source
.
getStartTime
());
copy
.
setEndTime
(
source
.
getEndTime
());
copy
.
setProcessingTime
(
source
.
getProcessingTime
());
copy
.
setTeardownTime
(
source
.
getTeardownTime
());
copy
.
setSetupTime
(
source
.
getSetupTime
());
copy
.
setPreTime
(
source
.
getPreTime
());
copy
.
setGeneDetails
(
deepCopyGeneDetailList
(
source
.
getGeneDetails
()));
return
copy
;
}
private
List
<
GeneDetail
>
deepCopyGeneDetailList
(
List
<
GeneDetail
>
source
)
{
return
source
==
null
?
new
ArrayList
<>()
:
source
.
stream
().
map
(
this
::
deepCopyGeneDetail
).
collect
(
Collectors
.
toList
());
}
private
GeneDetail
deepCopyGeneDetail
(
GeneDetail
source
)
{
if
(
source
==
null
)
return
null
;
GeneDetail
copy
=
new
GeneDetail
();
copy
.
setKey
(
source
.
getKey
());
copy
.
setStartTime
(
source
.
getStartTime
());
copy
.
setEndTime
(
source
.
getEndTime
());
return
copy
;
}
private
ScheduleChromosome
deepCopyScheduleChromosome
(
ScheduleChromosome
source
)
{
if
(
source
==
null
)
return
null
;
ScheduleChromosome
copy
=
new
ScheduleChromosome
(
source
.
getBaseTime
());
copy
.
setGenes
(
deepCopyGeneList
(
source
.
getGenes
()));
copy
.
setOrders
(
deepCopyOrderList
(
source
.
getOrders
()));
copy
.
setMachines
(
deepCopyMachineList
(
source
.
getMachines
()));
copy
.
setObjectiveValues
(
new
HashMap
<>(
source
.
getObjectiveValues
()));
copy
.
setFitness
(
source
.
getFitness
());
copy
.
setTardiness
(
source
.
getTardiness
());
return
copy
;
}
// ========================== 辅助类:StringUtils(对应C#字符串工具) ==========================
private
static
class
StringUtils
{
public
static
boolean
isEmpty
(
String
str
)
{
return
str
==
null
||
str
.
trim
().
isEmpty
();
}
}
}
\ No newline at end of file
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