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
f8d2a066
Commit
f8d2a066
authored
Aug 12, 2026
by
Tong Li
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
MP
parent
97f10b74
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
117 additions
and
44 deletions
+117
-44
CapacityConstraint.java
...a/com/aps/macroplanner/constraint/CapacityConstraint.java
+3
-0
MacroPlannerDataConverter.java
.../com/aps/macroplanner/data/MacroPlannerDataConverter.java
+49
-9
TestDataBuilder.java
src/main/java/com/aps/macroplanner/data/TestDataBuilder.java
+7
-12
UnitPeriod.java
src/main/java/com/aps/macroplanner/data/UnitPeriod.java
+17
-2
ResultWriter.java
src/main/java/com/aps/macroplanner/output/ResultWriter.java
+21
-11
SolutionPrinter.java
...ain/java/com/aps/macroplanner/output/SolutionPrinter.java
+19
-10
CapacityVariableBuilder.java
...om/aps/macroplanner/variable/CapacityVariableBuilder.java
+1
-0
No files found.
src/main/java/com/aps/macroplanner/constraint/CapacityConstraint.java
View file @
f8d2a066
...
...
@@ -30,6 +30,9 @@ public class CapacityConstraint {
Map
<
String
,
MPVariable
>
notMetVars
=
model
.
getCapacityNotMetVars
();
for
(
UnitPeriod
up
:
data
.
getUnitPeriods
())
{
// 无限产能单元: 无需产能限制
if
(
up
.
isUnlimited
())
continue
;
String
capKey
=
up
.
getKey
();
// --- 最大产能 ---
...
...
src/main/java/com/aps/macroplanner/data/MacroPlannerDataConverter.java
View file @
f8d2a066
...
...
@@ -913,6 +913,10 @@ public class MacroPlannerDataConverter {
}
// 为无产出工序的 MP 原材料补充"采购 Operation"
// 根据 MATERIAL_PURCHASE 创建供应商 unit:
// - 有 MATERIAL_PURCHASE → 每供应商一个 Operation, leadTimeDays = purchaseCycle
// - 无 MATERIAL_PURCHASE → 通用供应商 unit, relativeDuration=1, leadTimeDays=0, UnitPeriod 无限
for
(
Material
m
:
ctx
.
materialByMaterialId
.
values
())
{
if
(!
"MP"
.
equals
(
m
.
getMaterialTypeName
()))
{
continue
;
...
...
@@ -932,15 +936,40 @@ public class MacroPlannerDataConverter {
productSpMappings
.
add
(
new
ProductSpMapping
(
p
,
sp
));
ctx
.
finalSpByMaterialId
.
put
(
m
.
getId
(),
sp
);
}
int
leadTimeDays
=
m
.
getPurchaseLeadTime
()
>
0
?
m
.
getPurchaseLeadTime
()
:
1
;
Operation
procureOp
=
new
Operation
(
"OP_PROCURE_"
+
m
.
getId
(),
"采购-"
+
pickName
(
m
.
getName
(),
m
.
getId
()),
"UNIT_PROCURE_"
+
m
.
getId
(),
new
OperationOutput
(
p
,
sp
),
0.5
,
1.0
,
false
,
0.0
,
1.0
,
leadTimeDays
);
operations
.
add
(
procureOp
);
log
.
info
(
"为 MP 原材料 {} 补充采购 Operation (leadTime={}天)"
,
m
.
getId
(),
leadTimeDays
);
List
<
MaterialPurchase
>
purchases
=
m
.
getMaterialPurchases
();
if
(
purchases
!=
null
&&
!
purchases
.
isEmpty
())
{
// 有供应商: 按每个供应商创建独立的采购 Operation, leadTimeDays = purchaseCycle
for
(
MaterialPurchase
mp
:
purchases
)
{
String
unitId
=
"SUPPLIER_"
+
(
mp
.
getSupplyId
()
!=
null
?
mp
.
getSupplyId
()
:
"UNKNOWN"
);
int
leadTimeDays
=
mp
.
getPurchaseCycle
()
!=
null
?
mp
.
getPurchaseCycle
()
:
0
;
Operation
procureOp
=
new
Operation
(
"OP_PROCURE_"
+
m
.
getId
()
+
"_"
+
(
mp
.
getSupplyId
()
!=
null
?
mp
.
getSupplyId
()
:
"X"
),
"采购-"
+
pickName
(
m
.
getName
(),
m
.
getId
())
+
(
mp
.
getSupplyName
()
!=
null
?
"-"
+
mp
.
getSupplyName
()
:
""
),
Collections
.
singletonList
(
new
UnitOperation
(
unitId
,
0.5
,
false
,
0.0
,
1.0
)),
new
OperationOutput
(
p
,
sp
),
1.0
,
leadTimeDays
);
operations
.
add
(
procureOp
);
log
.
info
(
"为 MP 原材料 {} 创建采购 Operation (供应商={}, leadTime={}天)"
,
m
.
getId
(),
mp
.
getSupplyName
(),
leadTimeDays
);
}
}
else
{
// 无供应商: 使用通用供应商, 无限产能
String
unitId
=
"UNIT_DEFAULT_SUPPLIER"
;
ctx
.
unlimitedUnitIds
.
add
(
unitId
);
Operation
procureOp
=
new
Operation
(
"OP_PROCURE_"
+
m
.
getId
(),
"采购-"
+
pickName
(
m
.
getName
(),
m
.
getId
()),
Collections
.
singletonList
(
new
UnitOperation
(
unitId
,
0.5
,
false
,
0.0
,
1.0
)),
new
OperationOutput
(
p
,
sp
),
1.0
,
0
);
operations
.
add
(
procureOp
);
log
.
info
(
"为 MP 原材料 {} 创建通用采购 Operation (无供应商, 无限产能)"
,
m
.
getId
());
}
}
}
log
.
info
(
"构建 OperationInput: {}"
,
operationInputs
.
size
());
...
...
@@ -1051,6 +1080,13 @@ public class MacroPlannerDataConverter {
LocalDate
periodEnd
=
periodStart
.
plusDays
((
long
)
p
.
getDurationInDays
());
for
(
String
unitId
:
unitIds
)
{
// 无限产能设备 (通用供应商): 无需计算, 直接创建 unlimited UnitPeriod
if
(
ctx
.
unlimitedUnitIds
.
contains
(
unitId
))
{
unitPeriods
.
add
(
UnitPeriod
.
unlimited
(
unitId
,
p
));
continue
;
}
double
dailyCapacity
=
ctx
.
dailyCapacityByUnitId
.
getOrDefault
(
unitId
,
DEFAULT_DAILY_HOURS
);
// 节假日扣减
...
...
@@ -1222,6 +1258,10 @@ public class MacroPlannerDataConverter {
Map
<
String
,
Double
>
dailyCapacityByUnitId
=
new
HashMap
<>();
/** unitId → 节假日日期集合 */
Map
<
String
,
Set
<
LocalDate
>>
holidayDatesByUnitId
=
new
HashMap
<>();
/** unitId 集合: 产能无上限的设备 (如通用供应商, 无 MATERIAL_PURCHASE 时) */
Set
<
String
>
unlimitedUnitIds
=
new
HashSet
<>();
/** 排产周期数 (天), 从 ApsTimeConfig 计算 */
int
periodCount
=
7
;
}
...
...
src/main/java/com/aps/macroplanner/data/TestDataBuilder.java
View file @
f8d2a066
...
...
@@ -161,33 +161,29 @@ public class TestDataBuilder {
operationInputs
.
add
(
new
OperationInput
(
opS1
,
prodR2
,
spRM
,
2.0
));
// === 单元周期定义 (7 个生产单元, 不同可用工时) ===
// L1: 成品线, 最大可用工时
20
0h/周期
// L1: 成品线, 最大可用工时
1
0h/周期
for
(
Period
p
:
periods
)
{
unitPeriods
.
add
(
new
UnitPeriod
(
"L1"
,
p
,
0.0
,
10.0
,
false
));
}
for
(
Period
p
:
periods
)
{
unitPeriods
.
add
(
new
UnitPeriod
(
"L2"
,
p
,
0.0
,
10.0
,
false
));
}
// Unit_Semi: 半成品线, 最大产能
200
/周期
// Unit_Semi: 半成品线, 最大产能
10h
/周期
for
(
Period
p
:
periods
)
{
unitPeriods
.
add
(
new
UnitPeriod
(
"L3"
,
p
,
0.0
,
10.0
,
false
));
}
//
Unit_R1: 供应商 R1, 最大产能 150/周期
//
原材料供应商: 无限产能 (只要有需求就能供应)
for
(
Period
p
:
periods
)
{
unitPeriods
.
add
(
new
UnitPeriod
(
"SuA"
,
p
,
0.0
,
24
,
false
));
unitPeriods
.
add
(
UnitPeriod
.
unlimited
(
"SuA"
,
p
));
}
// Unit_R2: 供应商 R2, 最大产能 150/周期
for
(
Period
p
:
periods
)
{
unitPeriods
.
add
(
new
UnitPeriod
(
"SuB"
,
p
,
0.0
,
24
,
false
));
unitPeriods
.
add
(
UnitPeriod
.
unlimited
(
"SuB"
,
p
));
}
// Unit_R1_Alt: 备用供应商 R1, 最大产能 100/周期 (成本较高, 仅在主供应商不足时使用)
for
(
Period
p
:
periods
)
{
unitPeriods
.
add
(
new
UnitPeriod
(
"Su1"
,
p
,
0.0
,
24
,
false
));
unitPeriods
.
add
(
UnitPeriod
.
unlimited
(
"Su1"
,
p
));
}
// Unit_R2_Alt: 备用供应商 R2, 最大产能 100/周期 (成本较高, 仅在主供应商不足时使用)
for
(
Period
p
:
periods
)
{
unitPeriods
.
add
(
new
UnitPeriod
(
"Su2"
,
p
,
0.0
,
100.0
,
false
));
unitPeriods
.
add
(
UnitPeriod
.
unlimited
(
"Su2"
,
p
));
}
// === 初始库存 ===
...
...
@@ -408,6 +404,5 @@ public class TestDataBuilder {
if
(
reference
==
null
||
reference
.
getStartDate
()
==
null
)
return
null
;
LocalDate
targetDate
=
reference
.
getStartDate
().
minusDays
(
daysBack
);
return
getPeriodByDate
(
targetDate
);
}
}
\ No newline at end of file
src/main/java/com/aps/macroplanner/data/UnitPeriod.java
View file @
f8d2a066
...
...
@@ -10,13 +10,27 @@ public class UnitPeriod {
private
final
double
minCapacity
;
// 最小产能
private
final
double
maxCapacity
;
// 最大可用产能
private
final
boolean
hasMinCapacity
;
// 是否有最小产能约束
private
final
boolean
unlimited
;
// 产能是否无上限 (如原材料供应商)
public
UnitPeriod
(
String
unitId
,
Period
period
,
double
minCapacity
,
double
maxCapacity
,
boolean
hasMinCapacity
)
{
/** 完整构造器 */
public
UnitPeriod
(
String
unitId
,
Period
period
,
double
minCapacity
,
double
maxCapacity
,
boolean
hasMinCapacity
,
boolean
unlimited
)
{
this
.
unitId
=
unitId
;
this
.
period
=
period
;
this
.
minCapacity
=
minCapacity
;
this
.
maxCapacity
=
maxCapacity
;
this
.
maxCapacity
=
unlimited
?
Double
.
MAX_VALUE
:
maxCapacity
;
this
.
hasMinCapacity
=
hasMinCapacity
;
this
.
unlimited
=
unlimited
;
}
/** 有限产能构造器 (向后兼容) */
public
UnitPeriod
(
String
unitId
,
Period
period
,
double
minCapacity
,
double
maxCapacity
,
boolean
hasMinCapacity
)
{
this
(
unitId
,
period
,
minCapacity
,
maxCapacity
,
hasMinCapacity
,
false
);
}
/** 无限产能便捷构造器 */
public
static
UnitPeriod
unlimited
(
String
unitId
,
Period
period
)
{
return
new
UnitPeriod
(
unitId
,
period
,
0
,
0
,
false
,
true
);
}
public
String
getUnitId
()
{
return
unitId
;
}
...
...
@@ -24,6 +38,7 @@ public class UnitPeriod {
public
double
getMinCapacity
()
{
return
minCapacity
;
}
public
double
getMaxCapacity
()
{
return
maxCapacity
;
}
public
boolean
hasMinCapacity
()
{
return
hasMinCapacity
;
}
public
boolean
isUnlimited
()
{
return
unlimited
;
}
public
String
getKey
()
{
return
unitId
+
"_"
+
period
.
getIndex
();
...
...
src/main/java/com/aps/macroplanner/output/ResultWriter.java
View file @
f8d2a066
...
...
@@ -366,23 +366,33 @@ public class ResultWriter {
}
}
double
maxCap
=
up
.
getMaxCapacity
();
double
utilization
=
maxCap
>
0
?
capacityUsed
/
maxCap
:
0
;
double
overloaded
=
solutionValue
(
model
.
getCapacityOverloadedVars
(),
up
.
getKey
());
double
notMet
=
solutionValue
(
model
.
getCapacityNotMetVars
(),
up
.
getKey
());
pe
.
maxCapacity
=
maxCap
;
if
(
up
.
isUnlimited
())
{
pe
.
maxCapacity
=
-
1
;
// -1 表示无限
pe
.
utilization
=
-
1
;
// -1 表示不适用
pe
.
overloaded
=
0
;
pe
.
notMet
=
0
;
}
else
{
double
maxCap
=
up
.
getMaxCapacity
();
double
utilization
=
maxCap
>
0
?
capacityUsed
/
maxCap
:
0
;
double
overloaded
=
solutionValue
(
model
.
getCapacityOverloadedVars
(),
up
.
getKey
());
double
notMet
=
solutionValue
(
model
.
getCapacityNotMetVars
(),
up
.
getKey
());
pe
.
maxCapacity
=
maxCap
;
pe
.
utilization
=
utilization
;
pe
.
overloaded
=
overloaded
;
pe
.
notMet
=
notMet
;
}
pe
.
capacityUsed
=
capacityUsed
;
pe
.
utilization
=
utilization
;
pe
.
overloaded
=
overloaded
;
pe
.
notMet
=
notMet
;
ucr
.
getPeriodDetails
().
add
(
pe
);
// 累加汇总
ucr
.
setTotalMaxCapacity
(
ucr
.
getTotalMaxCapacity
()
+
maxCap
);
if
(!
up
.
isUnlimited
())
{
ucr
.
setTotalMaxCapacity
(
ucr
.
getTotalMaxCapacity
()
+
pe
.
maxCapacity
);
ucr
.
setTotalOverloaded
(
ucr
.
getTotalOverloaded
()
+
pe
.
overloaded
);
ucr
.
setTotalNotMet
(
ucr
.
getTotalNotMet
()
+
pe
.
notMet
);
}
ucr
.
setTotalCapacityUsed
(
ucr
.
getTotalCapacityUsed
()
+
capacityUsed
);
ucr
.
setTotalOverloaded
(
ucr
.
getTotalOverloaded
()
+
overloaded
);
ucr
.
setTotalNotMet
(
ucr
.
getTotalNotMet
()
+
notMet
);
}
// 计算整体利用率
...
...
src/main/java/com/aps/macroplanner/output/SolutionPrinter.java
View file @
f8d2a066
...
...
@@ -192,9 +192,13 @@ public class SolutionPrinter {
UnitPeriod
up
=
data
.
getUnitPeriod
(
unitId
,
p
);
if
(
up
==
null
)
continue
;
String
minStr
=
up
.
hasMinCapacity
()
?
String
.
format
(
"最小%.0fh/"
,
up
.
getMinCapacity
())
:
""
;
System
.
out
.
printf
(
" 【%s】产能%s%.0fh %s%n"
,
unitId
,
minStr
,
up
.
getMaxCapacity
(),
up
.
hasMinCapacity
()
?
"(强制最小)"
:
""
);
if
(
up
.
isUnlimited
())
{
System
.
out
.
printf
(
" 【%s】产能无限 (供应商)%n"
,
unitId
);
}
else
{
String
minStr
=
up
.
hasMinCapacity
()
?
String
.
format
(
"最小%.0fh/"
,
up
.
getMinCapacity
())
:
""
;
System
.
out
.
printf
(
" 【%s】产能%s%.0fh %s%n"
,
unitId
,
minStr
,
up
.
getMaxCapacity
(),
up
.
hasMinCapacity
()
?
"(强制最小)"
:
""
);
}
boolean
hasProduction
=
false
;
for
(
Operation
op
:
data
.
getOperations
())
{
...
...
@@ -205,13 +209,18 @@ public class SolutionPrinter {
if
(
ptQty
>
0.001
)
{
hasProduction
=
true
;
double
capacityUsed
=
ptQty
*
uo
.
getCapacityCoeff
();
double
utilPercent
=
up
.
getMaxCapacity
()
>
0
?
capacityUsed
/
up
.
getMaxCapacity
()
*
100
:
0
;
System
.
out
.
printf
(
" %s(%s): %.0f件 (耗时%.1fh) %s%n"
,
op
.
getName
(),
formatOutputProducts
(
op
),
ptQty
,
capacityUsed
,
uo
.
hasLotSize
()
?
String
.
format
(
", 批次%.0f"
,
uo
.
getLotSize
())
:
""
);
System
.
out
.
printf
(
" 利用率: %.0f/%.0f h (%.0f%%)%n"
,
capacityUsed
,
up
.
getMaxCapacity
(),
utilPercent
);
if
(
up
.
isUnlimited
())
{
System
.
out
.
printf
(
" %s(%s): %.0f件 (耗时%.1fh)%n"
,
op
.
getName
(),
formatOutputProducts
(
op
),
ptQty
,
capacityUsed
);
}
else
{
double
utilPercent
=
up
.
getMaxCapacity
()
>
0
?
capacityUsed
/
up
.
getMaxCapacity
()
*
100
:
0
;
System
.
out
.
printf
(
" %s(%s): %.0f件 (耗时%.1fh) %s%n"
,
op
.
getName
(),
formatOutputProducts
(
op
),
ptQty
,
capacityUsed
,
uo
.
hasLotSize
()
?
String
.
format
(
", 批次%.0f"
,
uo
.
getLotSize
())
:
""
);
System
.
out
.
printf
(
" 利用率: %.0f/%.0f h (%.0f%%)%n"
,
capacityUsed
,
up
.
getMaxCapacity
(),
utilPercent
);
}
}
}
}
...
...
src/main/java/com/aps/macroplanner/variable/CapacityVariableBuilder.java
View file @
f8d2a066
...
...
@@ -24,6 +24,7 @@ public class CapacityVariableBuilder {
public
static
void
create
(
MacroPlannerModel
model
,
TestDataBuilder
data
)
{
double
inf
=
MPSolver
.
infinity
();
for
(
UnitPeriod
up
:
data
.
getUnitPeriods
())
{
if
(
up
.
isUnlimited
())
continue
;
// 无限产能无需松弛变量
String
key
=
up
.
getKey
();
model
.
getCapacityOverloadedVars
().
put
(
key
,
model
.
getSolver
().
makeNumVar
(
0.0
,
inf
,
"CapOver_"
+
key
));
...
...
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