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
da795079
Commit
da795079
authored
Sep 22, 2026
by
Tong Li
Browse files
Options
Browse Files
Download
Plain Diff
MP-将kpi设置接入,优化器
parents
a6cb038c
e53a6cf9
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
332 additions
and
135 deletions
+332
-135
MacroPlannerResultController.java
...java/com/aps/controller/MacroPlannerResultController.java
+1
-4
MacroPlannerDataConverterRunner.java
...com/aps/macroplanner/MacroPlannerDataConverterRunner.java
+2
-2
MacroPlannerOptimizer.java
...main/java/com/aps/macroplanner/MacroPlannerOptimizer.java
+55
-16
DataValidator.java
src/main/java/com/aps/macroplanner/data/DataValidator.java
+4
-4
TestDataBuilder.java
src/main/java/com/aps/macroplanner/data/TestDataBuilder.java
+25
-16
MacroPlannerModel.java
...in/java/com/aps/macroplanner/model/MacroPlannerModel.java
+43
-0
KpiLib.java
src/main/java/com/aps/macroplanner/objective/KpiLib.java
+58
-0
KpiSetting.java
src/main/java/com/aps/macroplanner/objective/KpiSetting.java
+36
-0
ObjectiveBuilder.java
...java/com/aps/macroplanner/objective/ObjectiveBuilder.java
+52
-52
StrategyLevel.java
...in/java/com/aps/macroplanner/objective/StrategyLevel.java
+9
-5
ResultWriter.java
src/main/java/com/aps/macroplanner/output/ResultWriter.java
+4
-4
SolutionPrinter.java
...ain/java/com/aps/macroplanner/output/SolutionPrinter.java
+43
-32
No files found.
src/main/java/com/aps/controller/MacroPlannerResultController.java
View file @
da795079
...
@@ -64,9 +64,6 @@ import java.util.stream.Stream;
...
@@ -64,9 +64,6 @@ import java.util.stream.Stream;
@Slf4j
@Slf4j
public
class
MacroPlannerResultController
{
public
class
MacroPlannerResultController
{
@Autowired
private
com
.
aps
.
macroplanner
.
scene
.
MacroSceneMode
sceneMode
;
@Autowired
@Autowired
private
MpPispipResultPersistenceService
mpPispipResultPersistenceService
;
private
MpPispipResultPersistenceService
mpPispipResultPersistenceService
;
...
@@ -546,7 +543,7 @@ public class MacroPlannerResultController {
...
@@ -546,7 +543,7 @@ public class MacroPlannerResultController {
try
{
try
{
// 1. 数据转换: 数据库工艺物料类 → macroplanner 实体
// 1. 数据转换: 数据库工艺物料类 → macroplanner 实体
TestDataBuilder
data
=
macroPlannerDataConverter
.
convert
(
s
ceneMode
.
resolve
(
sid
)
);
TestDataBuilder
data
=
macroPlannerDataConverter
.
convert
(
s
id
);
result
.
put
(
"dataSummary"
,
buildDataSummary
(
data
));
result
.
put
(
"dataSummary"
,
buildDataSummary
(
data
));
// 2. 数据验证
// 2. 数据验证
...
...
src/main/java/com/aps/macroplanner/MacroPlannerDataConverterRunner.java
View file @
da795079
...
@@ -30,7 +30,7 @@ import org.springframework.context.ApplicationContext;
...
@@ -30,7 +30,7 @@ import org.springframework.context.ApplicationContext;
public
class
MacroPlannerDataConverterRunner
{
public
class
MacroPlannerDataConverterRunner
{
public
static
void
main
(
String
[]
args
)
{
public
static
void
main
(
String
[]
args
)
{
String
sceneId
=
(
args
.
length
>
0
)
?
args
[
0
]
:
""
;
String
sceneId
=
(
args
.
length
>
0
)
?
args
[
0
]
:
"
15b4cf5b-1224-418e-aa6f-1c643ea78d3c
"
;
System
.
out
.
println
(
"===== MACROPLANNER DATA CONVERTER RUNNER START ====="
);
System
.
out
.
println
(
"===== MACROPLANNER DATA CONVERTER RUNNER START ====="
);
System
.
out
.
println
(
"SceneId: "
+
sceneId
);
System
.
out
.
println
(
"SceneId: "
+
sceneId
);
...
@@ -40,7 +40,7 @@ public class MacroPlannerDataConverterRunner {
...
@@ -40,7 +40,7 @@ public class MacroPlannerDataConverterRunner {
MacroPlannerDataConverter
converter
=
ctx
.
getBean
(
MacroPlannerDataConverter
.
class
);
MacroPlannerDataConverter
converter
=
ctx
.
getBean
(
MacroPlannerDataConverter
.
class
);
// 1. 转换数据: 数据库工艺物料类 → macroplanner 实体
// 1. 转换数据: 数据库工艺物料类 → macroplanner 实体
TestDataBuilder
data
=
converter
.
convert
(
sceneId
);
TestDataBuilder
data
=
converter
.
convert
(
sceneId
,
8
);
// 2. 打印转换结果规模
// 2. 打印转换结果规模
System
.
out
.
println
(
"Data converted:"
);
System
.
out
.
println
(
"Data converted:"
);
...
...
src/main/java/com/aps/macroplanner/MacroPlannerOptimizer.java
View file @
da795079
package
com
.
aps
.
macroplanner
;
package
com
.
aps
.
macroplanner
;
import
com.aps.common.util.FileHelper
;
import
com.aps.common.util.FileHelper
;
import
com.aps.macroplanner.objective.KpiLib
;
import
com.aps.macroplanner.objective.KpiSetting
;
import
com.aps.macroplanner.output.dto.OptimizationResult
;
import
com.aps.macroplanner.output.dto.OptimizationResult
;
import
com.aps.service.MpPispipResultPersistenceService
;
import
com.aps.service.MpPispipResultPersistenceService
;
import
com.google.ortools.Loader
;
import
com.google.ortools.Loader
;
...
@@ -25,9 +27,12 @@ import java.time.LocalDateTime;
...
@@ -25,9 +27,12 @@ import java.time.LocalDateTime;
import
java.time.format.DateTimeFormatter
;
import
java.time.format.DateTimeFormatter
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.TreeMap
;
import
java.util.logging.ConsoleHandler
;
import
java.util.logging.ConsoleHandler
;
import
java.util.logging.Level
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
import
java.util.logging.Logger
;
import
java.util.stream.Collectors
;
/**
/**
* MacroPlanner 核心优化器 — 供应链产能规划混合整数规划(MIP)模型
* MacroPlanner 核心优化器 — 供应链产能规划混合整数规划(MIP)模型
...
@@ -197,11 +202,11 @@ public class MacroPlannerOptimizer {
...
@@ -197,11 +202,11 @@ public class MacroPlannerOptimizer {
writeLog
(
" [OK] 约束与KPI汇总创建完成"
);
writeLog
(
" [OK] 约束与KPI汇总创建完成"
);
// 3. 目标函数 (加权求和)
// 3. 目标函数 (加权求和)
ObjectiveBuilder
.
build
(
model
,
data
);
//
ObjectiveBuilder.build(model, data);
writeLog
(
" [OK] 目标函数创建完成"
);
writeLog
(
" [OK] 目标函数创建完成"
);
// 4. 导出 LP 模型文件
// 4. 导出 LP 模型文件
exportLpModel
();
//
exportLpModel();
writeLog
(
"\n模型统计: 变量="
+
model
.
getSolver
().
numVariables
()
writeLog
(
"\n模型统计: 变量="
+
model
.
getSolver
().
numVariables
()
+
", 约束="
+
model
.
getSolver
().
numConstraints
()
+
"\n"
);
+
", 约束="
+
model
.
getSolver
().
numConstraints
()
+
"\n"
);
...
@@ -279,12 +284,13 @@ public class MacroPlannerOptimizer {
...
@@ -279,12 +284,13 @@ public class MacroPlannerOptimizer {
final
long
startTimeMs
=
System
.
currentTimeMillis
();
final
long
startTimeMs
=
System
.
currentTimeMillis
();
// ========== 1. 前置参数校验 ==========
// ========== 1. 前置参数校验 ==========
KPIWeights
w
=
data
.
getKpiWeights
();
List
<
KpiSetting
>
w
=
data
.
getKpiSettings
();
List
<
StrategyLevel
>
levels
=
new
ArrayList
<>();
if
(
w
==
null
)
{
if
(
w
==
null
)
{
writeLog
(
"[ERROR] KPI权重配置为空,终止求解"
);
levels
=
defineLevels
(
data
.
getKpiWeights
());
return
;
}
else
{
levels
=
getKpiLevels
(
w
);
}
}
List
<
StrategyLevel
>
levels
=
defineLevels
(
w
);
if
(
levels
==
null
||
levels
.
isEmpty
())
{
if
(
levels
==
null
||
levels
.
isEmpty
())
{
writeLog
(
"[ERROR] 分层策略为空,终止求解"
);
writeLog
(
"[ERROR] 分层策略为空,终止求解"
);
return
;
return
;
...
@@ -427,31 +433,64 @@ public class MacroPlannerOptimizer {
...
@@ -427,31 +433,64 @@ public class MacroPlannerOptimizer {
// === Level 1: 需求满足 (最高优先级, 严格分层, slack=0%) ===
// === Level 1: 需求满足 (最高优先级, 严格分层, slack=0%) ===
StrategyLevel
l1
=
new
StrategyLevel
(
1
,
"需求满足"
,
0.0
);
StrategyLevel
l1
=
new
StrategyLevel
(
1
,
"需求满足"
,
0.0
);
l1
.
addKPI
(
"需求缺口"
,
model
.
getTotalFulfillment
(),
w
.
getFulfillmentWeight
());
l1
.
addKPI
(
KpiLib
.
Fulfillment
.
getEn
(),
KpiLib
.
Fulfillment
.
getCn
()
,
model
.
getTotalFulfillment
(),
w
.
getFulfillmentWeight
());
levels
.
add
(
l1
);
levels
.
add
(
l1
);
// === Level 2: 产能约束 (物理硬约束, 严格分层, slack=0%) ===
// === Level 2: 产能约束 (物理硬约束, 严格分层, slack=0%) ===
StrategyLevel
l2
=
new
StrategyLevel
(
2
,
"产能约束"
,
0.0
);
StrategyLevel
l2
=
new
StrategyLevel
(
2
,
"产能约束"
,
0.0
);
l2
.
addKPI
(
"产能超载"
,
model
.
getTotalUnitCapacity
(),
w
.
getUnitCapacityWeight
());
l2
.
addKPI
(
KpiLib
.
UnitCapacity
.
getEn
(),
KpiLib
.
Fulfillment
.
getCn
()
,
model
.
getTotalUnitCapacity
(),
w
.
getUnitCapacityWeight
());
levels
.
add
(
l2
);
levels
.
add
(
l2
);
// === Level 3: 业务KPI (允许 5% 退化, slack=5%) ===
// === Level 3: 业务KPI (允许 5% 退化, slack=5%) ===
StrategyLevel
l3
=
new
StrategyLevel
(
3
,
"业务KPI"
,
0.05
);
StrategyLevel
l3
=
new
StrategyLevel
(
3
,
"业务KPI"
,
0.05
);
l3
.
addKPI
(
"批次偏差"
,
model
.
getTotalLotSize
(),
w
.
getLotSizeWeight
());
l3
.
addKPI
(
KpiLib
.
LotSize
.
getEn
(),
KpiLib
.
LotSize
.
getCn
()
,
model
.
getTotalLotSize
(),
w
.
getLotSizeWeight
());
l3
.
addKPI
(
"目标库存偏差"
,
model
.
getTotalTargetInvLevel
(),
w
.
getTargetInventoryLevelWeight
());
l3
.
addKPI
(
KpiLib
.
TargetInvLevel
.
getEn
(),
KpiLib
.
TargetInvLevel
.
getCn
()
,
model
.
getTotalTargetInvLevel
(),
w
.
getTargetInventoryLevelWeight
());
l3
.
addKPI
(
"供应目标偏差"
,
model
.
getTotalSupplyTarget
(),
w
.
getSupplyTargetWeight
());
l3
.
addKPI
(
KpiLib
.
SupplyTarget
.
getEn
(),
KpiLib
.
SupplyTarget
.
getCn
()
,
model
.
getTotalSupplyTarget
(),
w
.
getSupplyTargetWeight
());
l3
.
addKPI
(
"销售优先级"
,
model
.
getTotalSalesDemandPriority
(),
l3
.
addKPI
(
KpiLib
.
SalesDemandPriority
.
getEn
(),
KpiLib
.
SalesDemandPriority
.
getCn
()
,
model
.
getTotalSalesDemandPriority
(),
w
.
getSalesDemandPriorityWeight
(),
true
);
// 负系数 = 最大化
w
.
getSalesDemandPriorityWeight
(),
true
);
// 负系数 = 最大化
levels
.
add
(
l3
);
levels
.
add
(
l3
);
// === Level 4: 软约束 (允许 10% 退化, slack=10%) ===
// === Level 4: 软约束 (允许 10% 退化, slack=10%) ===
StrategyLevel
l4
=
new
StrategyLevel
(
4
,
"软约束"
,
0.10
);
StrategyLevel
l4
=
new
StrategyLevel
(
4
,
"软约束"
,
0.10
);
l4
.
addKPI
(
"超库存"
,
model
.
getTotalMaxInventoryLevel
(),
w
.
getMaxInventoryLevelWeight
());
l4
.
addKPI
(
KpiLib
.
MaxInventoryLevel
.
getEn
(),
KpiLib
.
MaxInventoryLevel
.
getCn
()
,
model
.
getTotalMaxInventoryLevel
(),
w
.
getMaxInventoryLevelWeight
());
l4
.
addKPI
(
"欠库存"
,
model
.
getTotalMinInventoryLevel
(),
w
.
getMinInventoryLevelWeight
());
l4
.
addKPI
(
KpiLib
.
MinInventoryLevel
.
getEn
(),
KpiLib
.
MinInventoryLevel
.
getCn
()
,
model
.
getTotalMinInventoryLevel
(),
w
.
getMinInventoryLevelWeight
());
l4
.
addKPI
(
"最小供应不足"
,
model
.
getTotalMinSupply
(),
w
.
getMinSupplyWeight
());
l4
.
addKPI
(
KpiLib
.
MinSupply
.
getEn
(),
KpiLib
.
MinSupply
.
getCn
()
,
model
.
getTotalMinSupply
(),
w
.
getMinSupplyWeight
());
l4
.
addKPI
(
"最大供应超出"
,
model
.
getTotalMaxSupply
(),
w
.
getMaxSupplyWeight
());
l4
.
addKPI
(
KpiLib
.
MaxSupply
.
getEn
(),
KpiLib
.
MaxSupply
.
getCn
()
,
model
.
getTotalMaxSupply
(),
w
.
getMaxSupplyWeight
());
levels
.
add
(
l4
);
levels
.
add
(
l4
);
return
levels
;
}
private
List
<
StrategyLevel
>
getKpiLevels
(
List
<
KpiSetting
>
kpis
)
{
List
<
StrategyLevel
>
levels
=
new
ArrayList
<>();
Map
<
Integer
,
List
<
KpiSetting
>>
groupByLevelMap
=
kpis
.
stream
()
.
collect
(
Collectors
.
groupingBy
(
KpiSetting:
:
getLevel
,
//如果改成getter
TreeMap:
:
new
,
Collectors
.
toList
()
));
for
(
Map
.
Entry
<
Integer
,
List
<
KpiSetting
>>
entry
:
groupByLevelMap
.
entrySet
())
{
Integer
currentLevel
=
entry
.
getKey
();
List
<
KpiSetting
>
kpiGroup
=
entry
.
getValue
();
StrategyLevel
level
=
new
StrategyLevel
(
currentLevel
,
""
,
0.05
);
// 遍历当前分组里面每一个KPI
for
(
KpiSetting
kpi
:
kpiGroup
)
{
level
.
addKPI
(
kpi
.
code
,
kpi
.
name
,
model
.
getKpi
(
kpi
.
code
),
kpi
.
weight
);
}
levels
.
add
(
level
);
}
return
levels
;
return
levels
;
}
}
...
...
src/main/java/com/aps/macroplanner/data/DataValidator.java
View file @
da795079
...
@@ -232,7 +232,7 @@ public class DataValidator {
...
@@ -232,7 +232,7 @@ public class DataValidator {
Set
<
String
>
opIds
=
new
HashSet
<>();
Set
<
String
>
opIds
=
new
HashSet
<>();
for
(
Operation
op
:
data
.
getOperations
())
opIds
.
add
(
op
.
getId
());
for
(
Operation
op
:
data
.
getOperations
())
opIds
.
add
(
op
.
getId
());
int
maxPeriodIdx
=
data
.
getPeriods
().
size
()
-
1
;
//
int maxPeriodIdx = data.getPeriods().size() - 1;
// 销售需求
// 销售需求
for
(
SalesDemand
sd
:
data
.
getSalesDemands
())
{
for
(
SalesDemand
sd
:
data
.
getSalesDemands
())
{
...
@@ -242,9 +242,9 @@ public class DataValidator {
...
@@ -242,9 +242,9 @@ public class DataValidator {
if
(!
spIds
.
contains
(
sd
.
getStockingPoint
().
getId
()))
{
if
(!
spIds
.
contains
(
sd
.
getStockingPoint
().
getId
()))
{
errors
.
add
(
"销售需求引用不存在的库存点: "
+
sd
.
getStockingPoint
().
getId
());
errors
.
add
(
"销售需求引用不存在的库存点: "
+
sd
.
getStockingPoint
().
getId
());
}
}
if
(
sd
.
getPeriod
().
getIndex
()
>
maxPeriodIdx
)
{
//
if (sd.getPeriod().getIndex() > maxPeriodIdx) {
errors
.
add
(
"销售需求引用不存在的周期: "
+
sd
.
getPeriod
().
getIndex
());
//
errors.add("销售需求引用不存在的周期: " + sd.getPeriod().getIndex());
}
//
}
if
(
sd
.
getQuantity
()
<
0
)
{
if
(
sd
.
getQuantity
()
<
0
)
{
errors
.
add
(
"销售需求数量不能为负: "
+
sd
.
getProduct
().
getId
()
+
" P"
+
sd
.
getPeriod
().
getIndex
());
errors
.
add
(
"销售需求数量不能为负: "
+
sd
.
getProduct
().
getId
()
+
" P"
+
sd
.
getPeriod
().
getIndex
());
}
}
...
...
src/main/java/com/aps/macroplanner/data/TestDataBuilder.java
View file @
da795079
package
com
.
aps
.
macroplanner
.
data
;
package
com
.
aps
.
macroplanner
.
data
;
import
com.aps.macroplanner.objective.KpiSetting
;
import
java.util.*
;
import
java.util.*
;
import
java.time.LocalDate
;
import
java.time.LocalDate
;
...
@@ -57,7 +59,12 @@ public class TestDataBuilder {
...
@@ -57,7 +59,12 @@ public class TestDataBuilder {
/** 在途供应列表 (供应商已发货, 将在未来周期到货的固定量) */
/** 在途供应列表 (供应商已发货, 将在未来周期到货的固定量) */
protected
final
List
<
InTransitSupply
>
inTransitSupplies
=
new
ArrayList
<>();
protected
final
List
<
InTransitSupply
>
inTransitSupplies
=
new
ArrayList
<>();
/** KPI 权重 (子类可访问) */
/** KPI 权重 (子类可访问) */
protected
KPIWeights
kpiWeights
;
protected
KPIWeights
kpiWeights
;
protected
List
<
KpiSetting
>
kpiSettings
=
new
ArrayList
<>();
/** 初始库存: key = productId_spId, value = 初始库存量 (子类可访问) */
/** 初始库存: key = productId_spId, value = 初始库存量 (子类可访问) */
/** 初始库存列表 (子类可访问) */
/** 初始库存列表 (子类可访问) */
...
@@ -278,21 +285,20 @@ public class TestDataBuilder {
...
@@ -278,21 +285,20 @@ public class TestDataBuilder {
supplySpecs
.
add
(
new
SupplySpec
(
"Supply-R2-Alt"
,
40.0
,
20.0
,
80.0
,
supplySpecs
.
add
(
new
SupplySpec
(
"Supply-R2-Alt"
,
40.0
,
20.0
,
80.0
,
false
,
Arrays
.
asList
(
opR2Alt
)));
false
,
Arrays
.
asList
(
opR2Alt
)));
// === KPI 权重 ===
List
<
KpiSetting
>
kpis
=
new
ArrayList
<>();
kpiWeights
=
new
KPIWeights
(
kpis
.
add
(
new
KpiSetting
(
"需求满足"
,
"Fulfillment"
,
100
,
1
));
100.0
,
// fulfillmentWeight
kpis
.
add
(
new
KpiSetting
(
"产能"
,
"UnitCapacity"
,
20
,
1
));
10.0
,
// lotSizeWeight
kpis
.
add
(
new
KpiSetting
(
"批次"
,
"LotSize"
,
10
,
1
));
5.0
,
// maxInventoryLevelWeight
kpis
.
add
(
new
KpiSetting
(
"目标库存"
,
"TargetInvLevel"
,
8
,
1
));
5.0
,
// minInventoryLevelWeight
kpis
.
add
(
new
KpiSetting
(
"供应目标"
,
"SupplyTarget"
,
8
,
1
));
8.0
,
// targetInventoryLevelWeight
kpis
.
add
(
new
KpiSetting
(
"销售优先级"
,
"SalesDemandPriority"
,
1
,
1
));
20.0
,
// unitCapacityWeight
kpis
.
add
(
new
KpiSetting
(
"最大库存"
,
"MaxInventoryLevel"
,
5
,
1
));
8.0
,
// supplyTargetWeight
kpis
.
add
(
new
KpiSetting
(
"最小库存"
,
"MinInventoryLevel"
,
5
,
1
));
5.0
,
// minSupplyWeight
kpis
.
add
(
new
KpiSetting
(
"最小供应"
,
"MinSupply"
,
5
,
1
));
5.0
,
// maxSupplyWeight
kpis
.
add
(
new
KpiSetting
(
"最大供应"
,
"MaxSupply"
,
5
,
1
));
1.0
,
// salesDemandPriorityWeight
kpiSettings
=
kpis
;
20.0
,
// postponementPenaltyWeight
5.0
// processMaxQuantityWeight
);
}
}
// ==================== Getters ====================
// ==================== Getters ====================
...
@@ -395,8 +401,11 @@ public class TestDataBuilder {
...
@@ -395,8 +401,11 @@ public class TestDataBuilder {
public
List
<
InitialInventory
>
getInitialInventories
()
{
return
initialInventories
;
}
public
List
<
InitialInventory
>
getInitialInventories
()
{
return
initialInventories
;
}
public
List
<
KpiSetting
>
getKpiSettings
()
{
return
kpiSettings
;
}
public
KPIWeights
getKpiWeights
()
{
return
kpiWeights
;
}
public
KPIWeights
getKpiWeights
()
{
return
kpiWeights
;
}
/**
/**
* 获取初始库存量
* 获取初始库存量
* @param productId 产品ID
* @param productId 产品ID
...
...
src/main/java/com/aps/macroplanner/model/MacroPlannerModel.java
View file @
da795079
package
com
.
aps
.
macroplanner
.
model
;
package
com
.
aps
.
macroplanner
.
model
;
import
com.aps.macroplanner.objective.KpiLib
;
import
com.google.ortools.linearsolver.MPSolver
;
import
com.google.ortools.linearsolver.MPSolver
;
import
com.google.ortools.linearsolver.MPVariable
;
import
com.google.ortools.linearsolver.MPVariable
;
...
@@ -170,4 +171,46 @@ public class MacroPlannerModel {
...
@@ -170,4 +171,46 @@ public class MacroPlannerModel {
public
MPVariable
getTotalSalesDemandPriority
()
{
return
totalSalesDemandPriority
;
}
public
MPVariable
getTotalSalesDemandPriority
()
{
return
totalSalesDemandPriority
;
}
public
MPVariable
getTotalPostponementPenalty
()
{
return
totalPostponementPenalty
;
}
public
MPVariable
getTotalPostponementPenalty
()
{
return
totalPostponementPenalty
;
}
public
MPVariable
getTotalProcessMaxQuantity
()
{
return
totalProcessMaxQuantity
;
}
public
MPVariable
getTotalProcessMaxQuantity
()
{
return
totalProcessMaxQuantity
;
}
public
MPVariable
getKpi
(
String
code
)
{
MPVariable
kpivar
=
null
;
KpiLib
kpi
=
KpiLib
.
ofEn
(
code
);
switch
(
kpi
)
{
case
Fulfillment:
kpivar
=
totalFulfillment
;
break
;
case
UnitCapacity:
kpivar
=
totalUnitCapacity
;
break
;
case
LotSize:
kpivar
=
totalLotSize
;
break
;
case
TargetInvLevel:
kpivar
=
totalTargetInvLevel
;
break
;
case
SupplyTarget:
kpivar
=
totalSupplyTarget
;
break
;
case
SalesDemandPriority:
kpivar
=
totalSalesDemandPriority
;
break
;
case
MaxInventoryLevel:
kpivar
=
totalMaxInventoryLevel
;
break
;
case
MinInventoryLevel:
kpivar
=
totalMinInventoryLevel
;
break
;
case
MinSupply:
kpivar
=
totalMinSupply
;
break
;
case
MaxSupply:
kpivar
=
totalMaxSupply
;
break
;
}
return
kpivar
;
}
}
}
\ No newline at end of file
src/main/java/com/aps/macroplanner/objective/KpiLib.java
0 → 100644
View file @
da795079
package
com
.
aps
.
macroplanner
.
objective
;
import
java.util.Arrays
;
import
java.util.Map
;
import
java.util.stream.Collectors
;
/**
* 作者:佟礼
* 时间:2026-09-22
*/
public
enum
KpiLib
{
Fulfillment
(
"需求满足"
),
UnitCapacity
(
"产能"
),
LotSize
(
"批次"
),
TargetInvLevel
(
"目标库存"
),
SupplyTarget
(
"供应目标"
),
SalesDemandPriority
(
"销售优先级"
),
MaxInventoryLevel
(
"最大库存"
),
MinInventoryLevel
(
"最小库存"
),
MinSupply
(
"最小供应"
),
MaxSupply
(
"最大供应"
);
private
final
String
en
;
private
final
String
cn
;
KpiLib
(
String
cn
)
{
this
.
en
=
this
.
name
();
this
.
cn
=
cn
;
}
public
String
getEn
()
{
return
en
;
}
public
String
getCn
()
{
return
cn
;
}
/**
* 转为 Map<英文编码,中文名称>,用于批量翻译、表头转换
*/
public
static
Map
<
String
,
String
>
toEnCnMap
()
{
return
Arrays
.
stream
(
KpiLib
.
values
())
.
collect
(
Collectors
.
toMap
(
KpiLib:
:
getEn
,
KpiLib:
:
getCn
));
}
/**
* 根据英文编码获取枚举,返回null则未匹配
*/
public
static
KpiLib
ofEn
(
String
enName
)
{
for
(
KpiLib
dict
:
KpiLib
.
values
())
{
if
(
dict
.
getEn
().
equals
(
enName
))
{
return
dict
;
}
}
return
null
;
}
}
src/main/java/com/aps/macroplanner/objective/KpiSetting.java
0 → 100644
View file @
da795079
package
com
.
aps
.
macroplanner
.
objective
;
import
com.google.ortools.linearsolver.MPVariable
;
import
lombok.Data
;
/**
* 作者:佟礼
* 时间:2026-09-21
*/
@Data
public
class
KpiSetting
{
public
final
String
code
;
/**
* 该 KPI 在当前层级内的权重
*/
public
final
double
weight
;
public
final
Integer
level
;
/**
* KPI 名称
*/
public
final
String
name
;
public
KpiSetting
(
String
name
,
String
code
,
double
weight
,
Integer
level
)
{
this
.
name
=
name
;
this
.
code
=
code
;
this
.
weight
=
weight
;
this
.
level
=
level
;
}
}
src/main/java/com/aps/macroplanner/objective/ObjectiveBuilder.java
View file @
da795079
...
@@ -54,63 +54,63 @@ public class ObjectiveBuilder {
...
@@ -54,63 +54,63 @@ public class ObjectiveBuilder {
*/
*/
public
static
void
build
(
MacroPlannerModel
model
,
TestDataBuilder
data
)
{
public
static
void
build
(
MacroPlannerModel
model
,
TestDataBuilder
data
)
{
MPObjective
objective
=
model
.
getSolver
().
objective
();
MPObjective
objective
=
model
.
getSolver
().
objective
();
KPIWeights
w
=
data
.
getKpiWeights
();
//
KPIWeights w = data.getKpiWeights();
// ===== 惩罚项 (最小化: 正系数) =====
// ===== 惩罚项 (最小化: 正系数) =====
// Fulfillment: 需求松弛惩罚, 权重 100.0 (最高优先级)
// Fulfillment: 需求松弛惩罚, 权重 100.0 (最高优先级)
// 含义: 所有周期所有产品的需求松弛总和。值越小表示需求满足越好。
// 含义: 所有周期所有产品的需求松弛总和。值越小表示需求满足越好。
objective
.
setCoefficient
(
model
.
getTotalFulfillment
(),
w
.
getFulfillmentWeight
());
//
objective.setCoefficient(model.getTotalFulfillment(), w.getFulfillmentWeight());
//
// LotSize: 批次偏差惩罚, 权重 10.0
//
// LotSize: 批次偏差惩罚, 权重 10.0
// 含义: 所有操作所有周期的批次大小偏差总和。惩罚不按批次生产的量。
//
// 含义: 所有操作所有周期的批次大小偏差总和。惩罚不按批次生产的量。
objective
.
setCoefficient
(
model
.
getTotalLotSize
(),
w
.
getLotSizeWeight
());
//
objective.setCoefficient(model.getTotalLotSize(), w.getLotSizeWeight());
//
// MaxInventoryLevel: 超库存惩罚, 权重 5.0
//
// MaxInventoryLevel: 超库存惩罚, 权重 5.0
// 含义: 所有超标库存的总和。惩罚库存超过最大水平。
//
// 含义: 所有超标库存的总和。惩罚库存超过最大水平。
objective
.
setCoefficient
(
model
.
getTotalMaxInventoryLevel
(),
w
.
getMaxInventoryLevelWeight
());
//
objective.setCoefficient(model.getTotalMaxInventoryLevel(), w.getMaxInventoryLevelWeight());
//
// MinInventoryLevel: 欠库存(安全库存)惩罚, 权重 5.0
//
// MinInventoryLevel: 欠库存(安全库存)惩罚, 权重 5.0
// 含义: 所有低于最小库存的总和。惩罚库存低于安全水平。
//
// 含义: 所有低于最小库存的总和。惩罚库存低于安全水平。
objective
.
setCoefficient
(
model
.
getTotalMinInventoryLevel
(),
w
.
getMinInventoryLevelWeight
());
//
objective.setCoefficient(model.getTotalMinInventoryLevel(), w.getMinInventoryLevelWeight());
//
// TargetInventoryLevel: 目标库存偏差惩罚, 权重 8.0
//
// TargetInventoryLevel: 目标库存偏差惩罚, 权重 8.0
// 含义: 所有低于目标库存的总和。惩罚库存偏离目标水平。
//
// 含义: 所有低于目标库存的总和。惩罚库存偏离目标水平。
objective
.
setCoefficient
(
model
.
getTotalTargetInvLevel
(),
w
.
getTargetInventoryLevelWeight
());
//
objective.setCoefficient(model.getTotalTargetInvLevel(), w.getTargetInventoryLevelWeight());
//
// UnitCapacity: 产能超载惩罚, 权重 3.0
//
// UnitCapacity: 产能超载惩罚, 权重 3.0
// 含义: 所有设备所有周期的产能超载总和。惩罚超负荷生产。
//
// 含义: 所有设备所有周期的产能超载总和。惩罚超负荷生产。
objective
.
setCoefficient
(
model
.
getTotalUnitCapacity
(),
w
.
getUnitCapacityWeight
());
//
objective.setCoefficient(model.getTotalUnitCapacity(), w.getUnitCapacityWeight());
//
// SupplyTarget: 供应目标偏差惩罚, 权重 8.0
//
// SupplyTarget: 供应目标偏差惩罚, 权重 8.0
// 含义: 供应低于目标的总缺口。惩罚供应不足。
//
// 含义: 供应低于目标的总缺口。惩罚供应不足。
objective
.
setCoefficient
(
model
.
getTotalSupplyTarget
(),
w
.
getSupplyTargetWeight
());
//
objective.setCoefficient(model.getTotalSupplyTarget(), w.getSupplyTargetWeight());
//
// MinSupply: 最小供应不足惩罚, 权重 5.0
//
// MinSupply: 最小供应不足惩罚, 权重 5.0
// 含义: 供应低于最小值的总缺口。惩罚供应严重不足。
//
// 含义: 供应低于最小值的总缺口。惩罚供应严重不足。
objective
.
setCoefficient
(
model
.
getTotalMinSupply
(),
w
.
getMinSupplyWeight
());
//
objective.setCoefficient(model.getTotalMinSupply(), w.getMinSupplyWeight());
//
// MaxSupply: 最大供应超出惩罚, 权重 5.0
//
// MaxSupply: 最大供应超出惩罚, 权重 5.0
// 含义: 供应超出最大值的总量。惩罚过度供应。
//
// 含义: 供应超出最大值的总量。惩罚过度供应。
objective
.
setCoefficient
(
model
.
getTotalMaxSupply
(),
w
.
getMaxSupplyWeight
());
//
objective.setCoefficient(model.getTotalMaxSupply(), w.getMaxSupplyWeight());
//
// ===== 收益项 (最大化: 负系数, 因为 OR-Tools 默认最小化) =====
//
// ===== 收益项 (最大化: 负系数, 因为 OR-Tools 默认最小化) =====
//
// SalesDemandPriority: 销售需求优先级, 权重 1.0, 负系数 = 最大化
//
// SalesDemandPriority: 销售需求优先级, 权重 1.0, 负系数 = 最大化
// 含义: 按优先级加权的销售需求满足量。值越大表示满足的需求越多越好。
//
// 含义: 按优先级加权的销售需求满足量。值越大表示满足的需求越多越好。
// 因目标函数是最小化, 此项使用负系数 (最大化 = 加负号后最小化)。
//
// 因目标函数是最小化, 此项使用负系数 (最大化 = 加负号后最小化)。
objective
.
setCoefficient
(
model
.
getTotalSalesDemandPriority
(),
-
w
.
getSalesDemandPriorityWeight
());
//
objective.setCoefficient(model.getTotalSalesDemandPriority(), -w.getSalesDemandPriorityWeight());
//
// PostponementPenalty: 推迟惩罚, 权重 20.0 (简化版固定为 0)
//
// PostponementPenalty: 推迟惩罚, 权重 20.0 (简化版固定为 0)
// 含义: 对应原模型中的延迟销售需求惩罚。当前版本未实现推迟逻辑。
//
// 含义: 对应原模型中的延迟销售需求惩罚。当前版本未实现推迟逻辑。
objective
.
setCoefficient
(
model
.
getTotalPostponementPenalty
(),
w
.
getPostponementPenaltyWeight
());
//
objective.setCoefficient(model.getTotalPostponementPenalty(), w.getPostponementPenaltyWeight());
//
// ProcessMaxQuantity: 过程最大量惩罚, 权重 5.0 (简化版固定为 0)
//
// ProcessMaxQuantity: 过程最大量惩罚, 权重 5.0 (简化版固定为 0)
// 含义: 对应原模型中超出最大过程量的惩罚。当前版本未实现。
//
// 含义: 对应原模型中超出最大过程量的惩罚。当前版本未实现。
objective
.
setCoefficient
(
model
.
getTotalProcessMaxQuantity
(),
w
.
getProcessMaxQuantityWeight
());
//
objective.setCoefficient(model.getTotalProcessMaxQuantity(), w.getProcessMaxQuantityWeight());
//
// 设置为最小化目标
//
// 设置为最小化目标
objective
.
setMinimization
();
//
objective.setMinimization();
}
}
/**
/**
* 计算层级边界约束的上界。
* 计算层级边界约束的上界。
...
...
src/main/java/com/aps/macroplanner/objective/StrategyLevel.java
View file @
da795079
...
@@ -63,10 +63,14 @@ public class StrategyLevel {
...
@@ -63,10 +63,14 @@ public class StrategyLevel {
/** 是否为负向 KPI (越小越好 = 正常惩罚项; false = 正常惩罚项) */
/** 是否为负向 KPI (越小越好 = 正常惩罚项; false = 正常惩罚项) */
public
final
boolean
isNegative
;
public
final
boolean
isNegative
;
/** 编号 */
public
final
String
code
;
/** KPI 名称 (用于日志) */
/** KPI 名称 (用于日志) */
public
final
String
name
;
public
final
String
name
;
public
KPIEntry
(
String
name
,
MPVariable
variable
,
double
weight
,
boolean
isNegative
)
{
public
KPIEntry
(
String
code
,
String
name
,
MPVariable
variable
,
double
weight
,
boolean
isNegative
)
{
this
.
code
=
code
;
this
.
name
=
name
;
this
.
name
=
name
;
this
.
variable
=
variable
;
this
.
variable
=
variable
;
this
.
weight
=
weight
;
this
.
weight
=
weight
;
...
@@ -102,8 +106,8 @@ public class StrategyLevel {
...
@@ -102,8 +106,8 @@ public class StrategyLevel {
* @param variable KPI 汇总变量
* @param variable KPI 汇总变量
* @param weight 权重 (0 = 跳过)
* @param weight 权重 (0 = 跳过)
*/
*/
public
void
addKPI
(
String
name
,
MPVariable
variable
,
double
weight
)
{
public
void
addKPI
(
String
code
,
String
name
,
MPVariable
variable
,
double
weight
)
{
addKPI
(
name
,
variable
,
weight
,
false
);
addKPI
(
code
,
name
,
variable
,
weight
,
false
);
}
}
/**
/**
...
@@ -114,9 +118,9 @@ public class StrategyLevel {
...
@@ -114,9 +118,9 @@ public class StrategyLevel {
* @param weight 权重 (0 = 跳过)
* @param weight 权重 (0 = 跳过)
* @param isNegative 是否为负向 KPI (true = 最大化, 使用负系数)
* @param isNegative 是否为负向 KPI (true = 最大化, 使用负系数)
*/
*/
public
void
addKPI
(
String
name
,
MPVariable
variable
,
double
weight
,
boolean
isNegative
)
{
public
void
addKPI
(
String
code
,
String
name
,
MPVariable
variable
,
double
weight
,
boolean
isNegative
)
{
if
(
weight
>
0.0
&&
variable
!=
null
)
{
if
(
weight
>
0.0
&&
variable
!=
null
)
{
kpis
.
add
(
new
KPIEntry
(
name
,
variable
,
weight
,
isNegative
));
kpis
.
add
(
new
KPIEntry
(
code
,
name
,
variable
,
weight
,
isNegative
));
}
}
}
}
...
...
src/main/java/com/aps/macroplanner/output/ResultWriter.java
View file @
da795079
...
@@ -231,9 +231,9 @@ public class ResultWriter {
...
@@ -231,9 +231,9 @@ public class ResultWriter {
writeLog
(
"writeBomStructure"
);
writeLog
(
"writeBomStructure"
);
writeBomStructure
(
sceneId
);
writeBomStructure
(
sceneId
);
// 工序×物料×周期消耗量持久化
// 工序×物料×周期消耗量持久化
writeLog
(
"writeOperationDemands"
);
//
writeLog("writeOperationDemands");
List
<
OperationDemandResult
>
opDemands
=
buildOperationDemandResults
();
//
List<OperationDemandResult> opDemands = buildOperationDemandResults();
parquetUtil
.
write
(
opDemands
,
getOptimizationOperationDemand
(
sceneId
),
OperationDemandResult
.
class
);
//
parquetUtil.write(opDemands, getOptimizationOperationDemand(sceneId), OperationDemandResult.class);
return
true
;
return
true
;
// try {
// try {
...
@@ -535,7 +535,7 @@ public class ResultWriter {
...
@@ -535,7 +535,7 @@ public class ResultWriter {
// KPI + 统计
// KPI + 统计
writeLog
(
"Kpi"
);
writeLog
(
"Kpi"
);
result
.
setKpis
(
buildKpis
());
//
result.setKpis(buildKpis());
// result.setStatistics(buildStatistics());
// result.setStatistics(buildStatistics());
return
result
;
return
result
;
...
...
src/main/java/com/aps/macroplanner/output/SolutionPrinter.java
View file @
da795079
...
@@ -3,6 +3,7 @@ package com.aps.macroplanner.output;
...
@@ -3,6 +3,7 @@ package com.aps.macroplanner.output;
import
com.aps.common.util.FileHelper
;
import
com.aps.common.util.FileHelper
;
import
com.aps.macroplanner.data.*
;
import
com.aps.macroplanner.data.*
;
import
com.aps.macroplanner.model.MacroPlannerModel
;
import
com.aps.macroplanner.model.MacroPlannerModel
;
import
com.aps.macroplanner.objective.KpiLib
;
import
com.aps.macroplanner.objective.StrategyLevel
;
import
com.aps.macroplanner.objective.StrategyLevel
;
import
com.google.ortools.linearsolver.MPSolver
;
import
com.google.ortools.linearsolver.MPSolver
;
...
@@ -670,7 +671,7 @@ public class SolutionPrinter {
...
@@ -670,7 +671,7 @@ public class SolutionPrinter {
double
totalWeightedPenalty
=
0.0
;
double
totalWeightedPenalty
=
0.0
;
KPIWeights
w
=
data
.
getKpiWeights
();
KPIWeights
w
=
data
.
getKpiWeights
();
Map
<
String
,
Double
>
weights
=
new
HashMap
<>();
for
(
int
i
=
0
;
i
<
levels
.
size
();
i
++)
{
for
(
int
i
=
0
;
i
<
levels
.
size
();
i
++)
{
StrategyLevel
level
=
levels
.
get
(
i
);
StrategyLevel
level
=
levels
.
get
(
i
);
double
objValue
=
(
i
<
levelObjValues
.
size
())
?
levelObjValues
.
get
(
i
)
:
0.0
;
double
objValue
=
(
i
<
levelObjValues
.
size
())
?
levelObjValues
.
get
(
i
)
:
0.0
;
...
@@ -679,6 +680,7 @@ public class SolutionPrinter {
...
@@ -679,6 +680,7 @@ public class SolutionPrinter {
List
<
String
>
kpiNames
=
new
ArrayList
<>();
List
<
String
>
kpiNames
=
new
ArrayList
<>();
for
(
StrategyLevel
.
KPIEntry
kpi
:
level
.
getKpis
())
{
for
(
StrategyLevel
.
KPIEntry
kpi
:
level
.
getKpis
())
{
kpiNames
.
add
(
kpi
.
name
);
kpiNames
.
add
(
kpi
.
name
);
weights
.
put
(
kpi
.
code
,
kpi
.
weight
);
}
}
writeLog
(
"%-6d %-14s %-12s %-12.2f %s"
,
writeLog
(
"%-6d %-14s %-12s %-12.2f %s"
,
...
@@ -703,39 +705,48 @@ public class SolutionPrinter {
...
@@ -703,39 +705,48 @@ public class SolutionPrinter {
double
maxSupply
=
model
.
getTotalMaxSupply
().
solutionValue
();
double
maxSupply
=
model
.
getTotalMaxSupply
().
solutionValue
();
double
salesPriority
=
model
.
getTotalSalesDemandPriority
().
solutionValue
();
double
salesPriority
=
model
.
getTotalSalesDemandPriority
().
solutionValue
();
double
totalPenalty
=
fulfillment
*
w
.
getFulfillmentWeight
(
)
double
totalPenalty
=
fulfillment
*
w
eights
.
getOrDefault
(
KpiLib
.
Fulfillment
.
getEn
(),
0
d
)
+
lotSize
*
w
.
getLotSizeWeight
(
)
+
lotSize
*
w
eights
.
getOrDefault
(
KpiLib
.
LotSize
.
getEn
(),
0
d
)
+
maxInv
*
w
.
getMaxInventoryLevelWeight
(
)
+
maxInv
*
w
eights
.
getOrDefault
(
KpiLib
.
MinInventoryLevel
.
getEn
(),
0
d
)
+
minInv
*
w
.
getMinInventoryLevelWeight
(
)
+
minInv
*
w
eights
.
getOrDefault
(
KpiLib
.
MinInventoryLevel
.
getEn
(),
0
d
)
+
targetInv
*
w
.
getTargetInventoryLevelWeight
(
)
+
targetInv
*
w
eights
.
getOrDefault
(
KpiLib
.
TargetInvLevel
.
getEn
(),
0
d
)
+
capacity
*
w
.
getUnitCapacityWeight
(
)
+
capacity
*
w
eights
.
getOrDefault
(
KpiLib
.
UnitCapacity
.
getEn
(),
0
d
)
+
supplyTarget
*
w
.
getSupplyTargetWeight
(
)
+
supplyTarget
*
w
eights
.
getOrDefault
(
KpiLib
.
SupplyTarget
.
getEn
(),
0
d
)
+
minSupply
*
w
.
getMinSupplyWeight
(
)
+
minSupply
*
w
eights
.
getOrDefault
(
KpiLib
.
MinSupply
.
getEn
(),
0
d
)
+
maxSupply
*
w
.
getMaxSupplyWeight
(
)
+
maxSupply
*
w
eights
.
getOrDefault
(
KpiLib
.
MaxSupply
.
getEn
(),
0
d
)
-
salesPriority
*
w
.
getSalesDemandPriorityWeight
(
);
-
salesPriority
*
w
eights
.
getOrDefault
(
KpiLib
.
SalesDemandPriority
.
getEn
(),
0
d
);
writeLog
(
" 加权总惩罚: %.2f"
,
totalPenalty
);
writeLog
(
" 加权总惩罚: %.2f"
,
totalPenalty
);
writeLog
(
" 需求缺口: %.2f (权重%.0f × %.2f)"
,
fulfillment
*
w
.
getFulfillmentWeight
(),
w
.
getFulfillmentWeight
(),
fulfillment
);
for
(
Map
.
Entry
<
String
,
Double
>
entry
:
weights
.
entrySet
())
{
writeLog
(
" 产能超载: %.2f (权重%.0f × %.2f)"
,
String
key
=
entry
.
getKey
();
capacity
*
w
.
getUnitCapacityWeight
(),
w
.
getUnitCapacityWeight
(),
capacity
);
Double
weight
=
entry
.
getValue
();
writeLog
(
" 批次偏差: %.2f (权重%.0f × %.2f)"
,
KpiLib
kpi
=
KpiLib
.
ofEn
(
key
);
lotSize
*
w
.
getLotSizeWeight
(),
w
.
getLotSizeWeight
(),
lotSize
);
double
val
=
model
.
getKpi
(
key
).
solutionValue
();
writeLog
(
" 目标库存偏差: %.2f (权重%.0f × %.2f)"
,
writeLog
(
" %s: %.2f (权重%.0f × %.2f)"
,
targetInv
*
w
.
getTargetInventoryLevelWeight
(),
w
.
getTargetInventoryLevelWeight
(),
targetInv
);
kpi
.
getCn
(),
val
*
weight
,
val
,
val
);
writeLog
(
" 供应目标偏差: %.2f (权重%.0f × %.2f)"
,
}
supplyTarget
*
w
.
getSupplyTargetWeight
(),
w
.
getSupplyTargetWeight
(),
supplyTarget
);
writeLog
(
" 超库存: %.2f (权重%.0f × %.2f)"
,
maxInv
*
w
.
getMaxInventoryLevelWeight
(),
w
.
getMaxInventoryLevelWeight
(),
maxInv
);
// writeLog(" 产能超载: %.2f (权重%.0f × %.2f)",
writeLog
(
" 欠库存: %.2f (权重%.0f × %.2f)"
,
// capacity * weights.get(KpiLib.Fulfillment.getEn()), w.getUnitCapacityWeight(), capacity);
minInv
*
w
.
getMinInventoryLevelWeight
(),
w
.
getMinInventoryLevelWeight
(),
minInv
);
// writeLog(" 批次偏差: %.2f (权重%.0f × %.2f)",
writeLog
(
" 最小供应不足: %.2f (权重%.0f × %.2f)"
,
// lotSize * weights.get(KpiLib.Fulfillment.getEn()), w.getLotSizeWeight(), lotSize);
minSupply
*
w
.
getMinSupplyWeight
(),
w
.
getMinSupplyWeight
(),
minSupply
);
// writeLog(" 目标库存偏差: %.2f (权重%.0f × %.2f)",
writeLog
(
" 最大供应超出: %.2f (权重%.0f × %.2f)"
,
// targetInv * w.getTargetInventoryLevelWeight(), w.getTargetInventoryLevelWeight(), targetInv);
maxSupply
*
w
.
getMaxSupplyWeight
(),
w
.
getMaxSupplyWeight
(),
maxSupply
);
// writeLog(" 供应目标偏差: %.2f (权重%.0f × %.2f)",
writeLog
(
" 销售优先级(负): %.2f (权重%.0f × %.2f)"
,
// supplyTarget * w.getSupplyTargetWeight(), w.getSupplyTargetWeight(), supplyTarget);
salesPriority
*
w
.
getSalesDemandPriorityWeight
(),
// writeLog(" 超库存: %.2f (权重%.0f × %.2f)",
w
.
getSalesDemandPriorityWeight
(),
salesPriority
);
// maxInv * w.getMaxInventoryLevelWeight(), w.getMaxInventoryLevelWeight(), maxInv);
// writeLog(" 欠库存: %.2f (权重%.0f × %.2f)",
// minInv * w.getMinInventoryLevelWeight(), w.getMinInventoryLevelWeight(), minInv);
// writeLog(" 最小供应不足: %.2f (权重%.0f × %.2f)",
// minSupply * w.getMinSupplyWeight(), w.getMinSupplyWeight(), minSupply);
// writeLog(" 最大供应超出: %.2f (权重%.0f × %.2f)",
// maxSupply * w.getMaxSupplyWeight(), w.getMaxSupplyWeight(), maxSupply);
// writeLog(" 销售优先级(负): %.2f (权重%.0f × %.2f)",
// salesPriority * w.getSalesDemandPriorityWeight(),
// w.getSalesDemandPriorityWeight(), salesPriority);
}
}
// ==================== 辅助方法 ====================
// ==================== 辅助方法 ====================
...
...
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