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
25c58c5b
Commit
25c58c5b
authored
Apr 01, 2026
by
Tong Li
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
算法优化
parent
9d08cc4f
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
2278 additions
and
617 deletions
+2278
-617
ResourceGanttController.java
...ava/com/aps/controller/gantt/ResourceGanttController.java
+1
-1
ScheduleParams.java
src/main/java/com/aps/entity/Algorithm/ScheduleParams.java
+1
-1
GeneticAlgorithm.java
...main/java/com/aps/service/Algorithm/GeneticAlgorithm.java
+7
-7
GeneticDecoder.java
src/main/java/com/aps/service/Algorithm/GeneticDecoder.java
+96
-94
HillClimbing.java
src/main/java/com/aps/service/Algorithm/HillClimbing.java
+165
-133
HybridAlgorithm.java
src/main/java/com/aps/service/Algorithm/HybridAlgorithm.java
+3
-3
MachineCalculator.java
...ain/java/com/aps/service/Algorithm/MachineCalculator.java
+3
-0
OrderSortService.java
...main/java/com/aps/service/Algorithm/OrderSortService.java
+10
-10
SimulatedAnnealing.java
...in/java/com/aps/service/Algorithm/SimulatedAnnealing.java
+533
-48
TabuSearch.java
src/main/java/com/aps/service/Algorithm/TabuSearch.java
+2
-0
PlanResultService.java
src/main/java/com/aps/service/plan/PlanResultService.java
+1454
-317
PlanResultServiceTest.java
src/test/java/com/aps/demo/PlanResultServiceTest.java
+3
-3
No files found.
src/main/java/com/aps/controller/gantt/ResourceGanttController.java
View file @
25c58c5b
...
...
@@ -465,7 +465,7 @@ public class ResourceGanttController {
ParamValidator
.
validateSceneExists
(
sceneService
,
sceneId
);
planResultService
.
InsertOrderAuto
(
sceneId
,
newOrderData
);
//
planResultService.InsertOrderAuto(sceneId, newOrderData);
return
R
.
ok
(
"自动插单成功"
);
}
...
...
src/main/java/com/aps/entity/Algorithm/ScheduleParams.java
View file @
25c58c5b
...
...
@@ -17,7 +17,7 @@ public class ScheduleParams {
private
static
final
int
MIN_POPULATION_SIZE
=
10
;
private
static
final
int
MAX_POPULATION_SIZE
=
50
;
private
static
final
int
MIN_MAX_ITERATIONS
=
50
;
private
static
final
int
MAX_MAX_ITERATIONS
=
25
0
;
private
static
final
int
MAX_MAX_ITERATIONS
=
10
0
;
private
static
final
float
MIN_CROSSOVER_PROB
=
0.6f
;
private
static
final
float
MAX_CROSSOVER_PROB
=
0.9f
;
private
static
final
float
MIN_MUTATION_PROB
=
0.2f
;
...
...
src/main/java/com/aps/service/Algorithm/GeneticAlgorithm.java
View file @
25c58c5b
...
...
@@ -417,13 +417,13 @@ public class GeneticAlgorithm {
}
// 加载锁定工单到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
<>());
}
//
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<>());
//
}
decoder
.
decodeChromosomeWithCache
(
chromosome
);
if
(
chromosome
.
getFitness
()
==
0
)
{
...
...
src/main/java/com/aps/service/Algorithm/GeneticDecoder.java
View file @
25c58c5b
...
...
@@ -471,10 +471,14 @@ if(finishedOrder==null||finishedOrder.size()==0)
// 步骤2:按OperationSequencing顺序调度工序
Map
<
Integer
,
Integer
>
orderProcessCounter
=
new
HashMap
<>();
Map
<
Integer
,
Integer
>
orderLastEndTime
=
new
HashMap
<>();
Map
<
Integer
,
Entry
>
entryIndexById
=
new
HashMap
<>();
Map
<
Integer
,
List
<
Entry
>>
entrysBygroupId
=
new
HashMap
<>();
for
(
Entry
op
:
allOperations
)
{
int
groupId
=
op
.
getGroupId
();
orderProcessCounter
.
putIfAbsent
(
groupId
,
0
);
orderLastEndTime
.
putIfAbsent
(
groupId
,
0
);
entryIndexById
.
put
(
op
.
getId
(),
op
);
entrysBygroupId
.
computeIfAbsent
(
groupId
,
k
->
new
ArrayList
<>()).
add
(
op
);
}
// Map<Long, String> machineState = chromosome.getMachines().stream()
...
...
@@ -483,10 +487,12 @@ if(finishedOrder==null||finishedOrder.size()==0)
// List<Entry> allScheduledOps = new ArrayList<>();
// 缓存机器任务
Map
<
Long
,
CopyOnWriteArrayList
<
GAScheduleResult
>>
machineTasksCache
=
new
HashMap
<>();
for
(
Entry
op
:
allOperations
)
{
}
for
(
int
groupId
:
chromosome
.
getOperationSequencing
())
{
int
scheduledCount
=
orderProcessCounter
.
get
(
groupId
);
List
<
Entry
>
orderOps
=
allOperations
.
stream
()
.
filter
(
t
->
t
.
getGroupId
()
==
groupId
)
List
<
Entry
>
orderOps
=
entrysBygroupId
.
get
(
groupId
).
stream
()
.
sorted
(
Comparator
.
comparing
(
Entry:
:
getSequence
))
.
collect
(
Collectors
.
toList
());
...
...
@@ -1243,12 +1249,12 @@ return actualEndTime;
}
machineTasks
=
chromosome
.
getResult
().
stream
()
.
filter
(
t
->
t
.
getMachineId
()
==
machine
.
getId
())
.
sorted
(
Comparator
.
comparingInt
(
GAScheduleResult:
:
getStartTime
))
.
collect
(
Collectors
.
toCollection
(
CopyOnWriteArrayList:
:
new
));
machineTasksCache
.
put
(
machine
.
getId
(),
machineTasks
);
//
machineTasks =chromosome.getResult().stream()
//
.filter(t -> t.getMachineId() == machine.getId())
//
.sorted(Comparator.comparingInt(GAScheduleResult::getStartTime))
//
.collect(Collectors.toCollection(CopyOnWriteArrayList::new));
//
//
machineTasksCache.put(machine.getId(), machineTasks);
if
(
machineTasks
!=
null
&&
machineTasks
.
size
()>
0
&&
_globalParam
.
is_smoothChangeOver
())
{
...
...
@@ -1385,7 +1391,9 @@ return actualEndTime;
// FileHelper.writeLogFile(" 结束 "+ConvertTime(startTime)+"--"+ConvertTime(endTime)+" "+operation.getGroupId()+" : "+operation.getId()+",处理时间: " + processingTime + ", 后处理: " + teardownTime +
// ", 前处理: " + preTime + ", 换型: " + setupTime+ ", 数量: " + operation.getQuantity()+ ", 设备: "+machine.getId()+ ", 是否可中断: "+operation.getIsInterrupt());
machineTasksCache
.
remove
(
machine
.
getId
());
if
(
machineTasks
!=
null
)
{
machineTasks
.
add
(
result
);
}
return
endTime
;
}
...
...
@@ -2399,96 +2407,90 @@ if(MaterialRequirements==null||MaterialRequirements.size()==0)
private
void
calculateScheduleResult
(
Chromosome
chromosome
)
{
double
[]
Objectives
=
new
double
[
_globalParam
.
getObjectiveWeights
().
size
()];
double
[]
Objectives
=
new
double
[
_globalParam
.
getObjectiveWeights
().
size
()];
int
i
=
0
;
int
i
=
0
;
for
(
ObjectiveConfig
config
:
_globalParam
.
getObjectiveConfigs
())
{
if
(
config
.
isEnabled
())
{
if
(
config
.
getName
()==
GlobalParam
.
OBJECTIVE_MAKESPAN
)
{
// 1. 最早完工时间(最小化)
double
makespan
=
chromosome
.
getResult
().
stream
()
.
mapToInt
(
GAScheduleResult:
:
getEndTime
)
.
max
()
.
orElse
(
0
);
Objectives
[
i
]=
makespan
;
chromosome
.
setMakespan
(
makespan
);
}
if
(
config
.
getName
()==
GlobalParam
.
OBJECTIVE_TARDINESS
)
{
// 2. 交付期满足情况(最小化延迟)
double
tardiness
=
0
;
Map
<
Integer
,
List
<
GAScheduleResult
>>
orderGroups
=
chromosome
.
getResult
().
stream
()
.
collect
(
Collectors
.
groupingBy
(
GAScheduleResult:
:
getGroupId
));
for
(
Map
.
Entry
<
Integer
,
List
<
GAScheduleResult
>>
group
:
orderGroups
.
entrySet
())
{
int
groupId
=
group
.
getKey
();
int
orderCompletion
=
group
.
getValue
().
stream
()
.
mapToInt
(
GAScheduleResult:
:
getEndTime
)
.
max
()
.
orElse
(
0
);
List
<
String
>
orderIds
=
group
.
getValue
().
stream
()
.
map
(
GAScheduleResult:
:
getOrderId
)
.
distinct
()
.
sorted
()
.
collect
(
Collectors
.
toList
());
Order
order
=
chromosome
.
getOrders
().
stream
()
.
filter
(
t
->
orderIds
.
contains
(
t
.
getOrderId
()))
.
max
(
Comparator
.
comparing
(
Order:
:
getDueDate
))
.
orElse
(
null
);
if
(
order
.
isNewCreate
())
{
continue
;}
LocalDateTime
dueDateTime
=
order
.
getDueDate
();
LocalDateTime
completionTime
=
baseTime
.
plusSeconds
(
orderCompletion
);
if
(
completionTime
.
isAfter
(
dueDateTime
))
{
// 计算延迟小时数(修复时间计算)
long
hours
=
ChronoUnit
.
HOURS
.
between
(
dueDateTime
,
completionTime
);
long
minutes
=
ChronoUnit
.
MINUTES
.
between
(
dueDateTime
,
completionTime
)
%
60
;
tardiness
+=
hours
*
60
+
(
double
)
minutes
;
}
}
Objectives
[
i
]=
tardiness
;
chromosome
.
setDelayTime
(
tardiness
);
}
if
(
config
.
getName
()==
GlobalParam
.
OBJECTIVE_SETUP_TIME
)
{
// 3. 最小总换型时间
double
totalSetupTime
=
calculateTotalSetupTime
(
chromosome
);
chromosome
.
setTotalChangeoverTime
(
totalSetupTime
);
Objectives
[
i
]=
totalSetupTime
;
}
if
(
config
.
getName
()==
GlobalParam
.
OBJECTIVE_FLOW_TIME
)
{
// 4. 最小化总流程时间 所有工序加工时间的总和
double
totalFlowTime
=
calculateTotalFlowTime
(
chromosome
);
chromosome
.
setTotalFlowTime
(
totalFlowTime
);
Objectives
[
i
]=
totalFlowTime
;
}
if
(
config
.
getName
()==
GlobalParam
.
OBJECTIVE_MACHINE_LOAD
)
{
// 5. 机器负载均衡
double
machineLoadBalance
=
calculateMachineLoadBalance
(
chromosome
);
chromosome
.
setMachineLoadStd
(
machineLoadBalance
);
Objectives
[
i
]=
machineLoadBalance
;
}
i
++;
}
if
(
config
.
isEnabled
())
{
if
(
config
.
getName
()
==
GlobalParam
.
OBJECTIVE_MAKESPAN
)
{
// 1. 最早完工时间(最小化)
double
makespan
=
chromosome
.
getResult
().
stream
()
.
mapToInt
(
GAScheduleResult:
:
getEndTime
)
.
max
()
.
orElse
(
0
);
Objectives
[
i
]
=
makespan
;
chromosome
.
setMakespan
(
makespan
);
}
if
(
config
.
getName
()
==
GlobalParam
.
OBJECTIVE_TARDINESS
)
{
// 2. 交付期满足情况(最小化延迟)
double
tardiness
=
0
;
Map
<
Integer
,
List
<
GAScheduleResult
>>
orderGroups
=
chromosome
.
getResult
().
stream
()
.
collect
(
Collectors
.
groupingBy
(
GAScheduleResult:
:
getGroupId
));
for
(
Map
.
Entry
<
Integer
,
List
<
GAScheduleResult
>>
group
:
orderGroups
.
entrySet
())
{
int
groupId
=
group
.
getKey
();
int
orderCompletion
=
group
.
getValue
().
stream
()
.
mapToInt
(
GAScheduleResult:
:
getEndTime
)
.
max
()
.
orElse
(
0
);
List
<
String
>
orderIds
=
group
.
getValue
().
stream
()
.
map
(
GAScheduleResult:
:
getOrderId
)
.
distinct
()
.
sorted
()
.
collect
(
Collectors
.
toList
());
Order
order
=
chromosome
.
getOrders
().
stream
()
.
filter
(
t
->
orderIds
.
contains
(
t
.
getOrderId
()))
.
max
(
Comparator
.
comparing
(
Order:
:
getDueDate
))
.
orElse
(
null
);
if
(
order
.
isNewCreate
())
{
continue
;
}
LocalDateTime
dueDateTime
=
order
.
getDueDate
();
LocalDateTime
completionTime
=
baseTime
.
plusSeconds
(
orderCompletion
);
if
(
completionTime
.
isAfter
(
dueDateTime
))
{
// 计算延迟小时数(修复时间计算)
long
hours
=
ChronoUnit
.
HOURS
.
between
(
dueDateTime
,
completionTime
);
long
minutes
=
ChronoUnit
.
MINUTES
.
between
(
dueDateTime
,
completionTime
)
%
60
;
tardiness
+=
hours
*
60
+
(
double
)
minutes
;
}
}
Objectives
[
i
]
=
tardiness
;
chromosome
.
setDelayTime
(
tardiness
);
}
if
(
config
.
getName
()
==
GlobalParam
.
OBJECTIVE_SETUP_TIME
)
{
// 3. 最小总换型时间
double
totalSetupTime
=
calculateTotalSetupTime
(
chromosome
);
chromosome
.
setTotalChangeoverTime
(
totalSetupTime
);
Objectives
[
i
]
=
totalSetupTime
;
}
if
(
config
.
getName
()
==
GlobalParam
.
OBJECTIVE_FLOW_TIME
)
{
// 4. 最小化总流程时间 所有工序加工时间的总和
double
totalFlowTime
=
calculateTotalFlowTime
(
chromosome
);
chromosome
.
setTotalFlowTime
(
totalFlowTime
);
Objectives
[
i
]
=
totalFlowTime
;
}
if
(
config
.
getName
()
==
GlobalParam
.
OBJECTIVE_MACHINE_LOAD
)
{
// 5. 机器负载均衡
double
machineLoadBalance
=
calculateMachineLoadBalance
(
chromosome
);
chromosome
.
setMachineLoadStd
(
machineLoadBalance
);
Objectives
[
i
]
=
machineLoadBalance
;
}
i
++;
}
}
chromosome
.
setObjectives
(
Objectives
);
FitnessCalculator
fitnessCalculator
=
new
FitnessCalculator
();
if
(
chromosome
.
getFitnessLevel
()==
null
)
{
chromosome
.
setFitnessLevel
(
fitnessCalculator
.
calculateFitness
(
chromosome
,
_globalParam
));
}
FitnessCalculator
fitnessCalculator
=
new
FitnessCalculator
();
chromosome
.
setFitnessLevel
(
fitnessCalculator
.
calculateFitness
(
chromosome
,
_globalParam
));
}
private
double
calculateTotalFlowTime
(
Chromosome
chromosome
)
{
...
...
src/main/java/com/aps/service/Algorithm/HillClimbing.java
View file @
25c58c5b
...
...
@@ -11,6 +11,7 @@ import java.util.concurrent.CompletableFuture;
import
java.util.concurrent.CopyOnWriteArrayList
;
import
java.util.concurrent.ExecutorService
;
import
java.util.concurrent.Executors
;
import
java.util.stream.Collectors
;
/**
* 爬山法算法
...
...
@@ -38,7 +39,7 @@ public class HillClimbing {
// 按优先级从高到低处理
sortedPriorities
=
new
ArrayList
<>(
priorityGroups
.
keySet
());
Collections
.
sort
(
sortedPriorities
);
entrys
=
buildEntryKey
();
}
...
...
@@ -71,13 +72,54 @@ public class HillClimbing {
// 构建位置到Entry的映射:position -> Entry
Map
<
Integer
,
Entry
>
entryIndex
=
buildEntryIndex
(
current
,
entrys
);
boolean
improved
=
true
;
for
(
Double
priority
:
sortedPriorities
)
{
List
<
Entry
>
priorityOps
=
priorityGroups
.
get
(
priority
);
if
(
priorityOps
.
isEmpty
())
{
continue
;
}
// 1. 优先处理有多设备选项的工序(最有可能带来改进)
List
<
Entry
>
multiMachineOps
=
priorityOps
.
stream
()
.
filter
(
op
->
op
.
getMachineOptions
().
size
()
>
1
)
.
collect
(
Collectors
.
toList
());
if
(!
multiMachineOps
.
isEmpty
())
{
for
(
Entry
op
:
multiMachineOps
)
{
String
key
=
op
.
getGroupId
()
+
"_"
+
op
.
getSequence
();
Integer
maPos
=
MachinePositionIndex
.
get
(
key
);
if
(
maPos
==
null
)
continue
;
Chromosome
machineChange
=
generateMachineChange
(
current
,
op
.
getMachineOptions
(),
maPos
);
if
(
machineChange
!=
null
)
{
decode
(
decoder
,
machineChange
);
if
(
isBetter
(
machineChange
,
current
))
{
current
=
machineChange
;
if
(
isBetter
(
current
,
best
))
{
best
=
current
;
}
improved
=
true
;
positionIndex
=
buildPositionIndex
(
current
);
entryIndex
=
buildEntryIndex
(
current
,
entrys
);
MachinePositionIndex
=
buildEntryMachinePositionIndex
(
current
);
break
;
}
}
}
if
(
improved
)
break
;
}
if
(
improved
)
continue
;
// 2. 检查是否是单一订单(如果只有一个订单,不需要交换位置
Set
<
Integer
>
groupIds
=
priorityOps
.
stream
()
.
map
(
Entry:
:
getGroupId
)
.
collect
(
Collectors
.
toSet
());
if
(
groupIds
.
size
()
<=
1
)
{
continue
;
}
// 根据当前优先级的工序数确定迭代次数和step
int
priorityIterations
=
Math
.
max
(
5
,
priorityOps
.
size
()
/
2
);
// 200/10 =20
...
...
@@ -109,13 +151,7 @@ public class HillClimbing {
List
<
Chromosome
>
candidates
=
new
ArrayList
<>();
List
<
Chromosome
>
candidates1
=
new
ArrayList
<>();
if
(
MachineOptions
.
size
()
>
1
)
{
Chromosome
machineChange
=
generateMachineChange
(
current
,
MachineOptions
,
maPos
);
if
(
machineChange
!=
null
)
{
candidates
.
add
(
machineChange
);
candidates1
.
add
(
machineChange
);
}
}
// 向左多次移动(step 1, 2, 3...)
for
(
int
s
=
1
;
s
<=
stepCount
;
s
++)
{
...
...
@@ -197,185 +233,161 @@ public class HillClimbing {
Chromosome
best
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
// 构建位置索引映射:groupId_sequence -> position
Map
<
String
,
Integer
>
positionIndex
=
buildPositionIndex
(
current
);
Map
<
String
,
Integer
>
MachinePositionIndex
=
buildEntryMachinePositionIndex
(
current
);
int
totalCount
=
0
;
int
noImproveCount
=
0
;
int
maxNoImprove
=
50
;
// 连续50次没改进就提前停止
// 构建位置到Entry的映射:position -> Entry
Map
<
Integer
,
Entry
>
entryIndex
=
buildEntryIndex
(
current
,
entrys
);
boolean
improved
=
tru
e
;
Map
<
Integer
,
Entry
>
entryIndex
=
buildEntryIndex
(
current
,
entrys
);
boolean
improved
=
fals
e
;
for
(
Double
priority
:
sortedPriorities
)
{
List
<
Entry
>
priorityOps
=
priorityGroups
.
get
(
priority
);
if
(
priorityOps
.
isEmpty
())
{
continue
;
}
// 1. 优先处理有多设备选项的工序(最有可能带来改进)
List
<
Entry
>
multiMachineOps
=
priorityOps
.
stream
()
.
filter
(
op
->
op
.
getMachineOptions
().
size
()
>
1
)
.
collect
(
Collectors
.
toList
());
if
(!
multiMachineOps
.
isEmpty
())
{
for
(
Entry
op
:
multiMachineOps
)
{
String
key
=
op
.
getGroupId
()
+
"_"
+
op
.
getSequence
();
Integer
maPos
=
MachinePositionIndex
.
get
(
key
);
if
(
maPos
==
null
)
continue
;
Chromosome
machineChange
=
generateMachineChange
(
current
,
op
.
getMachineOptions
(),
maPos
);
if
(
machineChange
!=
null
)
{
decode
(
decoder
,
machineChange
);
if
(
isBetter
(
machineChange
,
current
))
{
current
=
machineChange
;
if
(
isBetter
(
current
,
best
))
{
best
=
ProductionDeepCopyUtil
.
deepCopy
(
current
,
Chromosome
.
class
);
}
improved
=
true
;
noImproveCount
=
0
;
positionIndex
=
buildPositionIndex
(
current
);
entryIndex
=
buildEntryIndex
(
current
,
entrys
);
MachinePositionIndex
=
buildEntryMachinePositionIndex
(
current
);
break
;
}
}
}
if
(
improved
)
break
;
}
if
(
improved
)
continue
;
// 2. 检查是否是单一订单(如果只有一个订单,不需要交换位置
Set
<
Integer
>
groupIds
=
priorityOps
.
stream
()
.
map
(
Entry:
:
getGroupId
)
.
collect
(
Collectors
.
toSet
());
if
(
groupIds
.
size
()
<=
1
)
{
continue
;
}
// 根据当前优先级的工序数确定迭代次数和step
int
priorityIterations
=
Math
.
max
(
5
,
priorityOps
.
size
()
/
2
);
int
priorityIterations
=
Math
.
max
(
5
,
priorityOps
.
size
()
/
2
);
// 200/10 =20
// 1
int
step
=
Math
.
max
(
1
,
(
int
)
Math
.
ceil
(
priorityOps
.
size
()
/
10.0
));
// 200/20=10;
//
int
stepCount
=
Math
.
max
(
1
,
(
int
)
Math
.
ceil
(
priorityOps
.
size
()
/
step
));
Set
<
Integer
>
Groupid
=
new
HashSet
<>();
int
noImproveCount
=
0
;
int
maxNoImprove
=
20
;
// 连续50次没改进就提前停止
Set
<
Integer
>
processedGroupIds
=
new
HashSet
<>();
for
(
int
pi
=
0
;
pi
<
priorityIterations
;
pi
++)
{
improved
=
false
;
// 随机取该优先级的工序
Entry
randomOp
=
priorityOps
.
get
(
rnd
.
nextInt
(
priorityOps
.
size
()));
if
(
processedGroupIds
.
contains
(
randomOp
.
getGroupId
()))
{
continue
;
}
processedGroupIds
.
add
(
randomOp
.
getGroupId
());
// 从索引中快速查找位置(O(1)复杂度)
String
key
=
randomOp
.
getGroupId
()
+
"_"
+
randomOp
.
getSequence
();
Integer
opPos
=
positionIndex
.
get
(
key
);
Integer
maPos
=
MachinePositionIndex
.
get
(
key
);
List
<
MachineOption
>
MachineOptions
=
randomOp
.
getMachineOptions
();
if
(
opPos
==
null
)
{
continue
;
}
List
<
Integer
>
os
=
current
.
getOperationSequencing
();
// 生成多个候选方案
List
<
Chromosome
>
candidates
=
new
ArrayList
<>();
if
(
MachineOptions
.
size
()>
1
)
{
Chromosome
machineChange
=
generateMachineChange
(
current
,
MachineOptions
,
maPos
);
if
(
machineChange
!=
null
)
{
candidates
.
add
(
machineChange
);
}
}
boolean
foundBetter
=
false
;
// 向左
多次移动(step 1, 2, 3...)
// 向左
逐步尝试
for
(
int
s
=
1
;
s
<=
stepCount
;
s
++)
{
int
targetPos
=
opPos
-
s
*
step
;
Entry
leftOp
=
entryIndex
.
get
(
targetPos
);
Entry
leftOp
=
entryIndex
.
get
(
opPos
-
s
*
step
);
if
(
leftOp
!=
null
&&
randomOp
.
getGroupId
()!=
leftOp
.
getGroupId
()
&&
Math
.
abs
(
leftOp
.
getPriority
()
-
priority
)
<=
0.001
)
{
Chromosome
newChromosome
=
swapAtDistance
(
current
,
opPos
,
-
s
*
step
);
candidates
.
add
(
newChromosome
);
if
(
leftOp
==
null
||
randomOp
.
getGroupId
()
==
leftOp
.
getGroupId
()
||
Math
.
abs
(
leftOp
.
getPriority
()
-
priority
)
>
0.001
)
{
break
;
}
if
(
MachineOptions
.
size
()>
1
)
{
Chromosome
machineChange
=
generateMachineChange
(
newChromosome
,
MachineOptions
,
maPos
);
if
(
machineChange
!=
null
)
{
candidates
.
add
(
machineChange
);
Chromosome
newChromosome
=
swapAtDistance
(
current
,
opPos
,
-
s
*
step
);
decode
(
decoder
,
newChromosome
);
}
if
(
isBetter
(
newChromosome
,
current
))
{
current
=
newChromosome
;
if
(
isBetter
(
current
,
best
))
{
best
=
ProductionDeepCopyUtil
.
deepCopy
(
current
,
Chromosome
.
class
);
}
}
else
{
improved
=
true
;
foundBetter
=
true
;
noImproveCount
=
0
;
positionIndex
=
buildPositionIndex
(
current
);
entryIndex
=
buildEntryIndex
(
current
,
entrys
);
break
;
}
if
(
candidates
.
size
()
>
5
)
{
batchDecode
(
decoder
,
candidates
,
machines
);
int
bestidx
=
Getbest
(
candidates
,
best
);
if
(
bestidx
>-
1
)
{
best
=
candidates
.
get
(
bestidx
);
current
=
ProductionDeepCopyUtil
.
deepCopy
(
best
,
Chromosome
.
class
);;
improved
=
true
;
// 更新索引
noImproveCount
=
0
;
positionIndex
=
buildPositionIndex
(
current
);
entryIndex
=
buildEntryIndex
(
current
,
entrys
);
break
;
}
candidates
.
clear
();
}
}
if
(
improved
)
{
break
;
}
if
(
foundBetter
)
break
;
// 向右
多次移动(step 1, 2, 3...)
// 向右
逐步尝试
for
(
int
s
=
1
;
s
<=
stepCount
;
s
++)
{
int
targetPos
=
opPos
+
s
*
step
;
Entry
rightOp
=
entryIndex
.
get
(
targetPos
);
Entry
rightOp
=
entryIndex
.
get
(
opPos
+
s
*
step
);
if
(
rightOp
!=
null
&&
randomOp
.
getGroupId
()
!=
rightOp
.
getGroupId
()
&&
Math
.
abs
(
rightOp
.
getPriority
()
-
priority
)
<=
0.001
)
{
Chromosome
newChromosome
=
swapAtDistance
(
current
,
opPos
,
s
*
step
)
;
candidates
.
add
(
newChromosome
);
if
(
rightOp
==
null
||
randomOp
.
getGroupId
()
==
rightOp
.
getGroupId
()
||
Math
.
abs
(
rightOp
.
getPriority
()
-
priority
)
>
0.001
)
{
break
;
}
if
(
MachineOptions
.
size
()>
1
)
{
Chromosome
machineChange
=
generateMachineChange
(
newChromosome
,
MachineOptions
,
maPos
);
if
(
machineChange
!=
null
)
{
candidates
.
add
(
machineChange
);
Chromosome
newChromosome
=
swapAtDistance
(
current
,
opPos
,
s
*
step
);
decode
(
decoder
,
newChromosome
);
}
if
(
isBetter
(
newChromosome
,
current
))
{
current
=
newChromosome
;
if
(
isBetter
(
current
,
best
))
{
best
=
ProductionDeepCopyUtil
.
deepCopy
(
current
,
Chromosome
.
class
);
}
}
else
{
improved
=
true
;
foundBetter
=
true
;
noImproveCount
=
0
;
positionIndex
=
buildPositionIndex
(
current
);
entryIndex
=
buildEntryIndex
(
current
,
entrys
);
break
;
}
if
(
candidates
.
size
()
>
5
)
{
batchDecode
(
decoder
,
candidates
,
machines
);
int
bestidx
=
Getbest
(
candidates
,
best
);
if
(
bestidx
>-
1
)
{
best
=
candidates
.
get
(
bestidx
);
current
=
ProductionDeepCopyUtil
.
deepCopy
(
best
,
Chromosome
.
class
);;
// 更新索引
noImproveCount
=
0
;
positionIndex
=
buildPositionIndex
(
current
);
entryIndex
=
buildEntryIndex
(
current
,
entrys
);
improved
=
true
;
break
;
}
candidates
.
clear
();
}
}
if
(
improved
)
{
break
;
}
if
(
candidates
.
size
()==
0
)
{
break
;
}
else
{
batchDecode
(
decoder
,
candidates
,
machines
);
}
int
bestidx
=
Getbest
(
candidates
,
best
);
if
(
bestidx
>-
1
)
if
(
foundBetter
)
break
;
noImproveCount
++;
totalCount
++;
if
(
noImproveCount
>
maxNoImprove
)
{
best
=
candidates
.
get
(
bestidx
);
current
=
ProductionDeepCopyUtil
.
deepCopy
(
best
,
Chromosome
.
class
);;
// 更新索引
noImproveCount
=
0
;
positionIndex
=
buildPositionIndex
(
current
);
entryIndex
=
buildEntryIndex
(
current
,
entrys
);
FileHelper
.
writeLogFile
(
String
.
format
(
"爬山法 - 提前停止:迭代%d次"
,
totalCount
));
improved
=
true
;
break
;
}
if
(
noImproveCount
>=
maxNoImprove
)
{
FileHelper
.
writeLogFile
(
String
.
format
(
"爬山法 - 提前停止:连续未优化 迭代%d次"
,
pi
+
1
));
noImproveCount
=
0
;
}
noImproveCount
++;
}
if
(
improved
)
break
;
}
return
best
;
}
...
...
@@ -497,7 +509,27 @@ boolean improved = true;
double
priority
=
op
.
getPriority
();
groups
.
computeIfAbsent
(
priority
,
k
->
new
ArrayList
<>()).
add
(
op
);
}
return
groups
;
// 过滤掉:设备只有一个且只有一个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
Set
<
Integer
>
groupIds
=
ops
.
stream
()
.
map
(
Entry:
:
getGroupId
)
.
collect
(
Collectors
.
toSet
());
// 如果两个条件都满足,过滤掉这个优先级组
if
(!(
allSingleMachine
&&
groupIds
.
size
()
<=
1
))
{
filteredGroups
.
put
(
entry
.
getKey
(),
ops
);
}
}
return
filteredGroups
;
}
/**
...
...
src/main/java/com/aps/service/Algorithm/HybridAlgorithm.java
View file @
25c58c5b
...
...
@@ -111,7 +111,7 @@ int opcount=allOperations.size();
// 初始化变邻域搜索
_vns
=
new
VariableNeighborhoodSearch
(
_GlobalParam
,
allOperations
,
globalOpList
,
_fitnessCalculator
,
_objectiveWeights
);
_hillClimbing
=
new
HillClimbing
(
allOperations
);
_simulatedAnnealing
=
new
SimulatedAnnealing
(
_GlobalParam
,
allOperations
,
globalOpList
,
_fitnessCalculator
,
_objectiveWeight
s
);
_simulatedAnnealing
=
new
SimulatedAnnealing
(
allOperation
s
);
_parallelLocalSearch
=
new
ParallelLocalSearch
(
_GlobalParam
,
allOperations
,
globalOpList
,
_fitnessCalculator
,
_objectiveWeights
);
_tabuSearch
=
new
TabuSearch
(
_GlobalParam
,
allOperations
,
globalOpList
,
_fitnessCalculator
,
_objectiveWeights
);
_tabuSearchWithSA
=
new
TabuSearchWithSA
(
_GlobalParam
,
allOperations
,
globalOpList
,
_fitnessCalculator
,
_objectiveWeights
);
...
...
@@ -142,7 +142,7 @@ int opcount=allOperations.size();
// 步骤2:对初始种群进行爬山法局部优化
if
(
population
.
size
()<
5
||
opcount
<
1
0
)
{
if
(
opcount
<
2
0
)
{
FileHelper
.
writeLogFile
(
"爬山法局部优化-----------开始-------"
);
GeneticDecoder
hillClimbingDecoder
=
new
GeneticDecoder
(
_GlobalParam
,
param
.
getBaseTime
(),
machines
,
orders
,
materials
,
machineScheduler
,
materialRequirementService
,
sceneId
);
...
...
@@ -156,7 +156,7 @@ int opcount=allOperations.size();
// 步骤2:对初始种群进行模拟退火+爬山法优化
GeneticDecoder
saDecoder1
=
new
GeneticDecoder
(
_GlobalParam
,
param
.
getBaseTime
(),
machines
,
orders
,
materials
,
machineScheduler
,
materialRequirementService
,
sceneId
);
if
(
population
.
size
()>
5
||
opcount
<
20
00
)
{
if
(
opcount
<
8
00
)
{
FileHelper
.
writeLogFile
(
"模拟退火+爬山法优化-----------开始-------"
);
Chromosome
saHcOptimized
=
_simulatedAnnealing
.
batchSearchGetMax
(
population
,
saDecoder1
,
machines
);
FileHelper
.
writeLogFile
(
"模拟退火+爬山法优化-----------结束-------"
);
...
...
src/main/java/com/aps/service/Algorithm/MachineCalculator.java
View file @
25c58c5b
...
...
@@ -934,6 +934,9 @@ public class MachineCalculator {
LocalDateTime
end
)
{
CopyOnWriteArrayList
<
TimeSegment
>
conflictIntervals
=
new
CopyOnWriteArrayList
<>();
// 1. 维护窗口冲突(优化重叠判断,更严谨)
if
(
machine
.
getMaintenanceWindows
()
!=
null
&&
!
machine
.
getMaintenanceWindows
().
isEmpty
())
{
// 过滤重叠的维护窗口并转换为TimeSegment
...
...
src/main/java/com/aps/service/Algorithm/OrderSortService.java
View file @
25c58c5b
...
...
@@ -474,18 +474,18 @@ public class OrderSortService {
if
(!
Objects
.
equals
(
prev
.
getSerie
(),
order
.
getSerie
()))
flags
.
append
(
"serie变 "
);
if
(!
Objects
.
equals
(
prev
.
getMaterialCode
(),
order
.
getMaterialCode
()))
flags
.
append
(
"material变"
);
}
costLog
.
append
(
String
.
format
(
" %2d. %s, routingId=%s, serie=%s, materialCode=%s, cost=%.0f %s\n"
,
(
i
+
1
),
order
.
getOrderCode
(),
order
.
getRoutingId
(),
order
.
getSerie
(),
order
.
getMaterialCode
(),
costToPrev
,
flags
.
toString
()));
//
costLog.append(String.format(" %2d. %s, routingId=%s, serie=%s, materialCode=%s, cost=%.0f %s\n",
//
(i + 1),
//
order.getOrderCode(),
//
order.getRoutingId(),
//
order.getSerie(),
//
order.getMaterialCode(),
//
costToPrev,
//
flags.toString()));
totalCost
+=
costToPrev
;
}
costLog
.
append
(
String
.
format
(
"[换线明细] 总换线成本 = %.0f\n"
,
totalCost
));
log
.
debug
(
costLog
.
toString
());
//
costLog.append(String.format("[换线明细] 总换线成本 = %.0f\n", totalCost));
//
log.debug(costLog.toString());
// ==================================
// 为最小化换线后的订单分配层级序号
...
...
src/main/java/com/aps/service/Algorithm/SimulatedAnnealing.java
View file @
25c58c5b
...
...
@@ -6,27 +6,32 @@ import com.aps.entity.Algorithm.*;
import
com.aps.entity.basic.Entry
;
import
com.aps.entity.basic.GlobalParam
;
import
com.aps.entity.basic.Machine
;
import
com.aps.entity.basic.MachineOption
;
import
java.util.*
;
import
java.util.concurrent.*
;
import
java.util.stream.Collectors
;
/**
* 模拟退火算法
*/
public
class
SimulatedAnnealing
{
private
final
Random
rnd
=
new
Random
();
private
GlobalParam
globalParam
;
private
List
<
Entry
>
allOperations
;
private
List
<
GlobalOperationInfo
>
globalOpList
;
private
FitnessCalculator
fitnessCalculator
;
private
ObjectiveWeights
objectiveWeights
;
public
SimulatedAnnealing
(
GlobalParam
globalParam
,
List
<
Entry
>
allOperations
,
List
<
GlobalOperationInfo
>
globalOpList
,
FitnessCalculator
fitnessCalculator
,
ObjectiveWeights
objectiveWeights
)
{
this
.
globalParam
=
globalParam
;
private
Map
<
String
,
Entry
>
entrys
;
private
Map
<
Integer
,
Entry
>
entrybyids
;
public
SimulatedAnnealing
(
List
<
Entry
>
allOperations
)
{
this
.
allOperations
=
allOperations
;
this
.
globalOpList
=
globalOpList
;
this
.
fitnessCalculator
=
fitnessCalculator
;
this
.
objectiveWeights
=
objectiveWeights
;
Map
<
Integer
,
Object
>
mp
=
buildEntryKey
();
entrys
=(
Map
<
String
,
Entry
>)
mp
.
get
(
1
);
entrybyids
=(
Map
<
Integer
,
Entry
>)
mp
.
get
(
2
);
}
private
final
ExecutorService
decodeExecutor
=
new
ThreadPoolExecutor
(
Runtime
.
getRuntime
().
availableProcessors
()
-
1
,
// 核心线程数=CPU-1,无切换开销
...
...
@@ -47,7 +52,7 @@ public class SimulatedAnnealing {
for
(
Chromosome
chromosome:
chromosomes
)
{
Chromosome
optimized
=
searchWithHillClimbing
(
chromosome
,
decoder
,
machines
);
saHcOptimized
.
add
(
optimized
);
break
;
}
return
saHcOptimized
;
}
...
...
@@ -63,57 +68,63 @@ public class SimulatedAnnealing {
}
/**
* 模拟退火搜索,当温度降低到一定程度后切换到爬山法
* 流程:模拟退火迭代 → 随机生成新排产 → 按概率接受 → 降温 → 温度低时爬山法求精 → 输出最优
*/
/**
* 模拟退火搜索,当温度降低到一定程度后切换到爬山法
* 流程:模拟退火全局探索(按概率接受劣解)→ 降温 → 温度低时爬山法局部求精 → 输出最优
*/
public
Chromosome
searchWithHillClimbing
(
Chromosome
chromosome
,
GeneticDecoder
decoder
,
List
<
Machine
>
machines
)
{
FileHelper
.
writeLogFile
(
"模拟退火+爬山法 - 开始执行"
);
Chromosome
current
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
Chromosome
best
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
writeKpi
(
best
);
// 初始化解码
Map
<
String
,
Entry
>
Entrys
=
buildEntryKey
(
current
);
FileHelper
.
writeLogFile
(
"模拟退火+爬山法 - 初始化索引完成"
);
// FileHelper.writeLogFile("模拟退火+爬山法 - 初始化解码完成");
// 初始化温度
- 优化速度:更快降温,更快切换到爬山法
// 初始化温度
double
temperature
=
100.0
;
double
coolingRate
=
0.95
;
double
temperatureThreshold
=
1.0
;
// 提高阈值,更快切换到爬山法
int
maxIterations
=
300
;
// 减少最大迭代次数
double
temperatureThreshold
=
1.0
;
int
maxIterations
=
300
;
int
noImproveCount
=
0
;
int
maxNoImprove
=
50
;
FileHelper
.
writeLogFile
(
String
.
format
(
"模拟退火+爬山法 - 参数配置:温度=%.1f, 降温率=%.2f, 阈值=%.1f, 最大迭代=%d"
,
temperature
,
coolingRate
,
temperatureThreshold
,
maxIterations
));
int
noImproveCount
=
0
;
int
maxNoImprove
=
50
;
// 连续50次没改进就提前停止
int
acceptCount
=
0
;
int
improveCount
=
0
;
for
(
int
i
=
0
;
i
<
maxIterations
;
i
++)
{
boolean
improved
=
false
;
// 1.
随机生成新排产(邻域解
)
Chromosome
neighbor
=
generateNeighbor
(
current
,
Entrys
);
// 1.
使用智能策略生成邻域解(找瓶颈工序/设备
)
Chromosome
neighbor
=
generateNeighbor
(
current
);
// 2. 解码
并计算适应度(只解码neighbor,current已经解码过了)
decode
(
decoder
,
neighbor
,
machines
);
// 2. 解码
decode
(
decoder
,
neighbor
,
machines
);
// 3. 计算能量差
(fitness差)
// 3. 计算能量差
double
energyDifference
=
calculateEnergyDifference
(
neighbor
,
current
);
// 4. 按概率接受新解
// - 更优:直接接受
// - 较差:概率接受(高温更容易接受)
// 4. 按概率接受新解(模拟退火核心:有概率接受劣解)
boolean
accepted
=
false
;
if
(
energyDifference
>
0
||
rnd
.
nextDouble
()
<
Math
.
exp
(
energyDifference
/
temperature
))
{
current
=
neighbor
;
accepted
=
true
;
acceptCount
++;
// 更新全局最优
if
(
isBetter
(
current
,
best
))
{
best
=
ProductionDeepCopyUtil
.
deepCopy
(
current
,
Chromosome
.
class
);
writeKpi
(
best
);
improved
=
true
;
improveCount
++;
noImproveCount
=
0
;
FileHelper
.
writeLogFile
(
String
.
format
(
"模拟退火+爬山法 - 迭代%d:找到更优解,fitness=%.4f"
,
i
,
best
.
getFitness
()));
}
}
...
...
@@ -123,10 +134,13 @@ public class SimulatedAnnealing {
// 5. 降温
temperature
*=
coolingRate
;
if
((
i
+
1
)
%
10
==
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. 提前停止条件:温度低于阈值 或 连续多次没改进
if
(
temperature
<
temperatureThreshold
||
noImproveCount
>=
maxNoImprove
)
{
String
stopReason
=
temperature
<
temperatureThreshold
?
"温度低于阈值"
:
"连续无改进达到上限"
;
...
...
@@ -134,20 +148,31 @@ public class SimulatedAnnealing {
stopReason
,
i
+
1
,
temperature
));
FileHelper
.
writeLogFile
(
"模拟退火+爬山法 - 切换到爬山法求精"
);
HillClimbing
hillClimbing
=
new
HillClimbing
(
allOperations
);
Chromosome
refined
=
hillClimbing
.
search
(
best
,
decoder
,
machines
);
HillClimbing
hillClimbing
=
new
HillClimbing
(
allOperations
);
Chromosome
refined
=
hillClimbing
.
search
(
best
,
decoder
,
machines
);
FileHelper
.
writeLogFile
(
"模拟退火+爬山法 - 爬山法求精完成"
);
// 返回爬山法求精后的结果
return
refined
;
}
}
FileHelper
.
writeLogFile
(
String
.
format
(
"模拟退火+爬山法 - 完成所有%d次迭代,最终fitness=%.4f"
,
maxIterations
,
best
.
getFitness
()));
FileHelper
.
writeLogFile
(
String
.
format
(
"模拟退火+爬山法 - 完成所有%d次迭代,最终fitness=%.4f"
,
maxIterations
,
best
.
getFitness
()));
// 7. 输出全局最优排产
return
best
;
}
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
));
}
/**
* 计算能量差(基于fitnessLevel数组的比较)
...
...
@@ -163,6 +188,77 @@ public class SimulatedAnnealing {
}
return
diff
;
}
/**
* 按优先级分组工序
*/
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
Set
<
Integer
>
groupIds
=
ops
.
stream
()
.
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
)
{
Map
<
String
,
Integer
>
index
=
new
HashMap
<>();
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
;
}
/**
* 构建位置索引:groupId_sequence -> Machines position
*/
private
Map
<
String
,
Integer
>
buildEntryMachinePositionIndex
(
Chromosome
chromosome
)
{
Map
<
String
,
Integer
>
index
=
new
HashMap
<>();
List
<
GlobalOperationInfo
>
globalOpList
=
chromosome
.
getGlobalOpList
();
for
(
int
i
=
0
;
i
<
globalOpList
.
size
();
i
++)
{
GlobalOperationInfo
globalOp
=
globalOpList
.
get
(
i
);
Entry
op
=
globalOp
.
getOp
();
int
groupId
=
op
.
getGroupId
();
int
count
=
op
.
getSequence
();
String
key
=
groupId
+
"_"
+
count
;
index
.
put
(
key
,
i
);
}
return
index
;
}
/**
* 构建位置->Entry索引
*/
...
...
@@ -188,39 +284,428 @@ public class SimulatedAnnealing {
/**
* 构建Entry索引:op.getGroupId() + "_" + op.getSequence() -> Entry
*/
private
Map
<
String
,
Entry
>
buildEntryKey
(
Chromosome
chromosome
)
{
private
Map
<
Integer
,
Object
>
buildEntryKey
()
{
Map
<
Integer
,
Object
>
index0
=
new
HashMap
<>();
Map
<
String
,
Entry
>
index
=
new
HashMap
<>();
List
<
Entry
>
allOps
=
chromosome
.
getAllOperations
()
;
Map
<
Integer
,
Entry
>
index2
=
new
HashMap
<>();
List
<
Entry
>
allOps
=
this
.
allOperations
;
for
(
Entry
op
:
allOps
)
{
String
key
=
op
.
getGroupId
()
+
"_"
+
op
.
getSequence
();
index
.
put
(
key
,
op
);
index2
.
put
(
op
.
getId
(),
op
);
}
index0
.
put
(
1
,
index
);
index0
.
put
(
2
,
index2
);
return
index0
;
}
/**
* 生成邻域解 - 智能策略:优先处理瓶颈工序/设备
* 策略:
* 1. 优先处理瓶颈设备上的工序(换设备)
* 2. 瓶颈设备上的工序往前移动
* 3. 非瓶颈设备上的工序往后移动(给瓶颈工序腾位置)
*/
private
Chromosome
generateNeighbor
(
Chromosome
chromosome
)
{
List
<
GAScheduleResult
>
results
=
chromosome
.
getResult
();
if
(
results
==
null
||
results
.
isEmpty
())
{
return
generateRandomNeighbor
(
chromosome
,
entrys
);
}
return
index
;
// 构建位置索引
Map
<
String
,
Integer
>
positionIndex
=
buildPositionIndex
(
chromosome
);
Map
<
Integer
,
Entry
>
positionToEntryIndex
=
buildPositionToEntryIndex
(
chromosome
,
entrys
);
Map
<
String
,
Integer
>
MachinePositionIndex
=
buildEntryMachinePositionIndex
(
chromosome
);
// 1. 找出瓶颈设备
Long
bottleneckMachineId
=
findBottleneckMachine
(
chromosome
);
if
(
bottleneckMachineId
!=
null
)
{
// 找出瓶颈设备上的工序
List
<
GAScheduleResult
>
bottleneckOps
=
findOpsOnBottleneckMachine
(
chromosome
,
bottleneckMachineId
);
if
(!
bottleneckOps
.
isEmpty
())
{
// 70%概率优先处理瓶颈设备
if
(
rnd
.
nextDouble
()
<
0.7
)
{
int
strategy
=
rnd
.
nextInt
(
10
);
if
(
strategy
<=
3
)
{
// 策略1:瓶颈设备上的工序换设备
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
);
}
}
}
}
// 默认策略:随机邻域
return
generateRandomNeighbor
(
chromosome
,
entrys
);
}
/**
* 识别瓶颈设备(利用率最高的设备)
*/
private
Long
findBottleneckMachine
(
Chromosome
chromosome
)
{
Map
<
Long
,
Double
>
utilization
=
calculateMachineUtilization
(
chromosome
);
if
(
utilization
.
isEmpty
())
{
return
null
;
}
return
utilization
.
entrySet
().
stream
()
.
max
(
Map
.
Entry
.
comparingByValue
())
.
map
(
Map
.
Entry
::
getKey
)
.
orElse
(
null
);
}
/**
* 查找在瓶颈设备上的工序
*/
private
List
<
GAScheduleResult
>
findOpsOnBottleneckMachine
(
Chromosome
chromosome
,
Long
bottleneckMachineId
)
{
if
(
bottleneckMachineId
==
null
)
{
return
new
ArrayList
<>();
}
return
chromosome
.
getResult
().
stream
()
.
filter
(
r
->
r
.
getMachineId
()
==
bottleneckMachineId
)
.
collect
(
Collectors
.
toList
());
}
/**
* 计算设备利用率
*/
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
()
.
mapToInt
(
GAScheduleResult:
:
getEndTime
)
.
max
()
.
orElse
(
1
);
Map
<
Long
,
List
<
GAScheduleResult
>>
machineResults
=
results
.
stream
()
.
collect
(
Collectors
.
groupingBy
(
GAScheduleResult:
:
getMachineId
));
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
)
{
// 优先选择有多设备选项的工序
List
<
GAScheduleResult
>
candidates
=
bottleneckOps
.
stream
()
.
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中的位置
int
maPos
=
-
1
;
Entry
entry
=
entrybyids
.
get
(
selectedOp
.
getOperationId
());
if
(
entry
!=
null
&&
entry
.
getMachineOptions
().
size
()
>
1
)
{
maPos
=
MachinePositionIndex
.
get
(
entry
.
getGroupId
()
+
"_"
+
entry
.
getSequence
());
if
(
maPos
>=
0
)
{
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
())
{
int
newMachineSeq
=
availableMachines
.
get
(
rnd
.
nextInt
(
availableMachines
.
size
()));
ms
.
set
(
idx
,
newMachineSeq
);
neighbor
.
setMachineSelection
(
ms
);
}
}
}
return
neighbor
;
}
/**
* 尝试将瓶颈设备上的工序往前移动
*/
private
Chromosome
tryMoveBottleneckOpForward
(
Chromosome
chromosome
,
List
<
GAScheduleResult
>
bottleneckOps
,
Map
<
String
,
Integer
>
positionIndex
,
Map
<
Integer
,
Entry
>
positionToEntryIndex
,
Map
<
String
,
Entry
>
entrys
)
{
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
);
}
// 随机选择一个非瓶颈工序
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
generateNeighbor
(
Chromosome
chromosome
,
Map
<
String
,
Entry
>
entrys
)
{
private
Chromosome
moveOperationForward
(
Chromosome
chromosome
,
Map
<
Integer
,
Entry
>
originalPositionIndex
,
int
pos
,
int
steps
)
{
Chromosome
neighbor
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
List
<
Integer
>
os
=
neighbor
.
getOperationSequencing
();
if
(
pos
<=
0
||
pos
>=
os
.
size
())
{
return
neighbor
;
}
// 获取要移动的工序和目标位置的工序(基于原始chromosome)
Entry
opToMove
=
originalPositionIndex
.
get
(
pos
);
if
(
opToMove
==
null
)
{
return
neighbor
;
}
int
targetPos
=
Math
.
max
(
0
,
pos
-
steps
);
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
;
}
/**
* 将工序往后移动
*/
private
Chromosome
moveOperationBackward
(
Chromosome
chromosome
,
Map
<
Integer
,
Entry
>
originalPositionIndex
,
int
pos
,
int
steps
)
{
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
);
if
(
opToMove
==
null
)
{
return
neighbor
;
}
int
targetPos
=
Math
.
min
(
os
.
size
()
-
1
,
pos
+
steps
);
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
;
}
/**
* 将工序往前插入(不交换,直接插入到目标位置)
*/
private
Chromosome
insertOperationForward
(
Chromosome
chromosome
,
int
pos
,
int
steps
,
Map
<
String
,
Entry
>
entrys
)
{
Chromosome
neighbor
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
List
<
Integer
>
os
=
neighbor
.
getOperationSequencing
();
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
);
if
(
leftOp
!=
null
&&
opToMove
.
getGroupId
()
==
leftOp
.
getGroupId
())
{
break
;
}
if
(
leftOp
!=
null
&&
Math
.
abs
(
leftOp
.
getPriority
()
-
opToMove
.
getPriority
())
>
0.001
)
{
break
;
}
finalTargetPos
=
i
;
}
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
);
return
generateSwapNeighbor
(
chromosome
,
entrys
);
case
1
:
return
generateReverseNeighbor
(
chromosome
,
entrys
);
return
generateReverseNeighbor
(
chromosome
,
entrys
);
case
2
:
return
generateInsertNeighbor
(
chromosome
,
entrys
);
return
generateInsertNeighbor
(
chromosome
,
entrys
);
case
3
:
return
generateMachineChangeNeighbor
(
chromosome
);
default
:
return
generateSwapNeighbor
(
chromosome
,
entrys
);
return
generateSwapNeighbor
(
chromosome
,
entrys
);
}
}
/**
* 生成交换邻域解 - 只在相同优先级的工序之间交换
*/
...
...
@@ -332,7 +817,7 @@ public class SimulatedAnnealing {
List
<
Integer
>
ms
=
neighbor
.
getMachineSelection
();
if
(!
ms
.
isEmpty
())
{
int
idx
=
rnd
.
nextInt
(
ms
.
size
());
GlobalOperationInfo
globalOp
=
globalOpList
.
get
(
idx
);
GlobalOperationInfo
globalOp
=
chromosome
.
getGlobalOpList
()
.
get
(
idx
);
Entry
op
=
globalOp
.
getOp
();
if
(
op
.
getMachineOptions
().
size
()
>
1
)
{
...
...
src/main/java/com/aps/service/Algorithm/TabuSearch.java
View file @
25c58c5b
...
...
@@ -29,6 +29,8 @@ public class TabuSearch {
this
.
fitnessCalculator
=
fitnessCalculator
;
this
.
objectiveWeights
=
objectiveWeights
;
this
.
tabuList
=
new
ArrayList
<>();
// 工序越多,禁忌表越长(适配1000+工序)
this
.
tabuListSize
=
Math
.
min
(
50
,
allOperations
.
size
()
/
30
);
}
/**
...
...
src/main/java/com/aps/service/plan/PlanResultService.java
View file @
25c58c5b
This source diff could not be displayed because it is too large. You can
view the blob
instead.
src/test/java/com/aps/demo/PlanResultServiceTest.java
View file @
25c58c5b
...
...
@@ -39,9 +39,9 @@ public class PlanResultServiceTest {
// TestSortService sortService=new TestSortService();
// sortService.test1();
// nsgaiiUtils.Test();
//
planResultService.execute2("0428340BB4F540938F1FB5599F03E8A4");//2000
planResultService
.
execute2
(
"C8B533BD8944405B9A2F8823C575C204"
);
//500
//
planResultService.execute2("EFDD34E4B5BC434BAEAE6A84DFCD4E7B");//20
planResultService
.
execute2
(
"0428340BB4F540938F1FB5599F03E8A4"
);
//2000
//
planResultService.execute2("C8B533BD8944405B9A2F8823C575C204");//500
//
planResultService.execute2("EFDD34E4B5BC434BAEAE6A84DFCD4E7B");//20
// planResultService.execute2("00E0C5D3E4AD4F36B56C39395906618D");
// planResultService.execute2("92BB773E1E2447C99D8176C991D5C9D2");
...
...
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