You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于JuMP与GLPK的员工调度优化代码报错排查

JuMP+GLPK员工调度优化问题错误修复

问题背景

使用JuMP与GLPK求解员工调度优化问题,目标是确定满足工作量需求的最优员工数量,代码基于数学模型编写,但运行时出现类型转换错误,无法得到结果。

出错代码

using JuMP
using GLPK

# Constants and parameters
Wjk = [[19, 19, 14]  [16, 16, 11]  [22, 22, 16]  [22, 22, 16]  [22, 22, 16]  [22, 22, 16]  [22, 22, 16]]   # Workload requirement
Ajk = 8  # Some constant value for Ajk
M = 395  # Total number of shifts

# Create a JuMP model
model = Model(GLPK.Optimizer)

# Decision variables for shift allocation
@variable(model, x[1:N, 1:3, 1:7] >= 0, Int)  # Decision variable for shift allocation


# Objective function
@objective(model, Min, sum(x[i, j, k] for i in 1:N, j in 1:3, k in 1:7))


# Objective function
#@objective(model, Min, sum(x[i, j, k] for i in 1:N for j in 1:3 for k in 1:7))


# Constraints
for i in 1:N
    for k in 1:7
        @constraint(model, sum(x[i, j, k] for j in 1:3) <= 2)  # Constraints (8) - (10)
        @constraint(model, sum(x[i, j, k]) + sum(x[i, 2, mod(k + 1, 7) + 1] for j in 2:3) <= 2)  # Constraint (9)
        @constraint(model, sum(x[i, 3, k]) + sum(x[i, 1, mod(k + 1, 7) + 1]) +
                    sum(x[i, 2, (mod(k + 1, 7)) + 1]) <= 2)  # Constraint (10)
    end
end


for j in 1:3
    for k in 1:7
        @constraint(model, sum(x[i, j, k] for i in 1:N) >= Wjk[k, j])  # Constraint (11)
        @constraint(model, sum(x[i, j, k] for i in 1:N) <= Wjk[k, j] + Ajk)  # Constraint (12)
    end
end

for i in 1:N
    @constraint(model, sum(x[i, j, ((i - 1) % 7) + 1] + x[i, j, i % 7 + 1] for j in 1:3) == 0)  # Constraint (13)
end

for i in 1:N
    for k in 1:5
        @constraint(model, sum(x[i, j, (i + k) % 7 + 1] for j in 1:3) >= 1)  # Constraint (14)
    end
end

@constraint(model, sum(x[i, j, k] for i in 1:N for j in 1:3 for k in 1:7) == M)

# Solve the optimization problem
optimize!(model)

# Display the results
println("Optimal Number of Employees: ", value(N))
println("Optimal Shift Allocation:")
for i in 1:value(N)
    for j in 1:3
        for k in 1:7
            if value(x[i, j, k]) > 0.5
                println("Employee $i, Shift $j on Day $k")
            end
        end
    end
end

错误信息

ERROR: MethodError: Cannot `convert` an object of type VariableRef to an object of type Float64
Closest candidates are:
convert(::Type{T}, ::Base.TwicePrecision) where T<:Number at twiceprecision.jl:250
convert(::Type{T}, ::AbstractChar) where T<:Number at char.jl:180
convert(::Type{T}, ::CartesianIndex{1}) where T<:Number at multidimensional.jl:136
...
Stacktrace:
[1] MathOptInterface.GreaterThan{Float64}(lower::VariableRef)
MathOptInterface C:\Users\doriiido\.julia\packages\MathOptInterface\IiXiU\src\sets.jl:171
[2] _moi_constrain_variable(moi_backend::MathOptInterface.Utilities.CachingOptimizer{MathOptInterface.Bridges.LazyBridgeOptimizer{GLPK.Optimizer}, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}}, index::MathOptInterface.VariableIndex, info::VariableInfo{VariableRef, Float64, Float64, Float64}, #unused#::Type{Float64})
JuMP C:\Users\doriiido\.julia\packages\JuMP\ToPd2\src\variables.jl:1754
[3] _moi_add_variable(moi_backend::MathOptInterface.Utilities.CachingOptimizer{MathOptInterface.Bridges.LazyBridgeOptimizer{GLPK.Optimizer}, MathOptInterface.Utilities.UniversalFallback{MathOptInterface.Utilities.Model{Float64}}}, model::Model, v::ScalarVariable{VariableRef, Float64, Float64, Float64}, name::String)
JuMP C:\Users\doriiido\.julia\packages\JuMP\ToPd2\src\variables.jl:1737
[4] add_variable(model::Model, v::ScalarVariable{VariableRef, Float64, Float64, Float64}, name::String)
JuMP C:\Users\doriiido\.julia\packages\JuMP\ToPd2\src\variables.jl:1726
[5] macro expansion
C:\Users\doriiido\.julia\packages\JuMP\ToPd2\src\macros.jl:1213 [inlined]
[6] top-level scope
Untitled-2:13

错误根源

  1. N未定义且误用:代码中直接使用1:N作为数组维度,但从未定义N。JuMP不允许用变量作为数组维度(数组大小必须在建模前确定),导致编译器将N误判为变量引发类型转换错误。
  2. Wjk维度错误:原定义方式生成1行21列数组,与需求的7天×3班维度不符,后续索引Wjk[k,j]逻辑错误。
  3. 目标函数偏差:原目标是最小化总班次,而非实际需求的最小化员工数量。
  4. 约束逻辑漏洞:部分约束的索引计算存在歧义,且缺少未雇佣员工不可排班的约束。

修复后的代码

using JuMP
using GLPK

# Constants and parameters
# 7天×3班的工作量需求:每行对应1天,每列对应1个班次
Wjk = [
    19 19 14;
    16 16 11;
    22 22 16;
    22 22 16;
    22 22 16;
    22 22 16;
    22 22 16
]
Ajk = 8       # 每班允许的最大超额人数
N_max = 100   # 员工数量的上界(可根据实际情况调整)

# 创建JuMP模型
model = Model(GLPK.Optimizer)

# 决策变量
# y[i]:是否雇佣第i个员工(1=雇佣,0=不雇佣)
@variable(model, y[1:N_max], Bin)
# x[i,j,k]:第i个员工在第k天是否排第j个班次(1=排,0=不排)
@variable(model, x[1:N_max, 1:3, 1:7], Bin)

# 目标函数:最小化雇佣的员工数量
@objective(model, Min, sum(y[i] for i in 1:N_max))

# 约束1:未雇佣的员工不能排班
for i in 1:N_max
    for j in 1:3
        for k in 1:7
            @constraint(model, x[i,j,k] <= y[i])
        end
    end
end

# 约束2:每个员工每天最多排2个班次
for i in 1:N_max
    for k in 1:7
        @constraint(model, sum(x[i,j,k] for j in 1:3) <= 2)
    end
end

# 约束3:连续班次限制(原约束9-10)
for i in 1:N_max
    for k in 1:7
        next_day = k % 7 + 1
        # 当天排2/3班 + 次日排2班 ≤2
        @constraint(model, sum(x[i,j,k] for j in 2:3) + x[i,2,next_day] <= 2)
        # 当天排3班 + 次日排1/2班 ≤2
        @constraint(model, x[i,3,k] + sum(x[i,j,next_day] for j in 1:2) <= 2)
    end
end

# 约束4:每班每日的员工数量满足工作量需求
for j in 1:3
    for k in 1:7
        @constraint(model, sum(x[i,j,k] for i in 1:N_max) >= Wjk[k,j])
        @constraint(model, sum(x[i,j,k] for i in 1:N_max) <= Wjk[k,j] + Ajk)
    end
end

# 约束5:新员工前2天不排班(原约束13)
for i in 1:N_max
    day1 = (i-1) % 7 + 1
    day2 = i % 7 + 1
    @constraint(model, sum(x[i,j,day1] + x[i,j,day2] for j in 1:3) == 0)
end

# 约束6:每个员工连续5天至少排1个班(原约束14)
for i in 1:N_max
    for k in 1:5
        target_day = (i + k) % 7 + 1
        @constraint(model, sum(x[i,j,target_day] for j in 1:3) >= 1)
    end
end

# 可选约束:总班次数量固定(根据需求启用)
# @constraint(model, sum(x[i,j,k] for i in 1:N_max, j in 1:3, k in 1:7) == 395)

# 求解模型
optimize!(model)

# 输出结果
optimal_employees = sum(value(y[i]) for i in 1:N_max)
println("最优员工数量: ", optimal_employees)
println("每班每日分配员工数:")
for k in 1:7
    for j in 1:3
        total = sum(value(x[i,j,k]) for i in 1:N_max)
        println("第$k天 第$j班: $total 人")
    end
end

# 可选:输出详细排班情况
# println("\n详细排班:")
# for i in 1:N_max
#     if value(y[i]) > 0.5
#         println("员工$i:")
#         for k in 1:7
#             shifts = [j for j in 1:3 if value(x[i,j,k]) > 0.5]
#             if !isempty(shifts)
#                 println("  第$k天: 班次$(join(shifts, ","))")
#             end
#         end
#     end
# end

修复说明

  1. 员工数量处理:通过设定员工数量上界N_max,引入二进制变量y[i]标记是否雇佣,既规避了变量作为数组维度的问题,又实现了最小化员工数量的目标。
  2. 维度修正:将Wjk调整为7行3列矩阵,符合7天×3班的索引逻辑。
  3. 约束完善:添加未雇佣员工不可排班的约束,修正连续班次限制的索引计算,保留原有的工作量、新员工排班限制等约束。
  4. 结果输出:直接计算并输出每班每日的员工总数,匹配需求。

内容的提问来源于stack exchange,提问作者Dddd97

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 13:24:51