JuMP中嵌套函数调用及produce转Channel问题求助
解决JuMP scan_maker函数的闭包、非方阵输出及produce替代问题
嘿,我看你在实现基于JuMP的扫描生成器时碰到了几个头疼的问题——闭包调用不对、非方阵A输出乱码,还有废弃的produce不知道怎么替换成Channel。别急,我一步步帮你理清楚怎么解决:
1. 把废弃的produce换成Channel
Julia里的produce/consume早就被淘汰啦,现在都用Channel来实现迭代生成值。你可以把scan函数改成返回一个Channel,然后在循环里用put!把生成的v发送出去——记得要发copy(v)哦,不然后面修改v会把已经传出去的值也改掉,坑死人。
修改后的scan核心逻辑如下:
function scan() return Channel() do ch i = 1 init = 1 while i > 0 # 原有循环逻辑不变,直到需要输出v的地方 if i >= level # 发送v的副本,避免后续修改影响已传递的值 put!(ch, copy(v)) continue else setupperbound(x[i], v[i]) setlowerbound(x[i], v[i]) i += 1 end end end end
之后调用时,直接用for val in scan()就能遍历生成的所有结果了。
2. 搞定非方阵A的无意义输出问题
当A是非方阵时,约束数和变量数不匹配,你的扫描逻辑很容易出问题:
- 约束数少于变量数时,部分变量可能会无界,
round(Int, getvalue(x[i]))会得到Inf/-Inf转成的极端整数,导致后续循环逻辑混乱 - 旧代码里直接断言求解结果只能是
:Optimal或:Unbounded,但非方阵场景下可能出现其他状态,触发断言失败
给你两个关键修改点:
- 先判断变量是否无界,避免无效的round操作:
x_val = value(x[i]) ub[i] = isinf(x_val) ? typemax(Int) : round(Int, x_val) - 给非方阵场景加个警告,提前提示风险:
function scan_maker(A) m, n = size(A) if m != n @warn "A不是方阵,扫描逻辑可能出现异常,请确认需求是否匹配" end # 原有代码... end
3. 修正闭包调用的问题
你看到的那些无意义输出,其实是因为直接打印了scan()返回的Channel对象,而不是迭代它获取里面的值。正确的调用流程应该是:
# 1. 创建生成器 A = rand(2,4) # 非方阵示例 setc, scan = scan_maker(A) # 2. 设置约束下界 c = [0.5, 1.0] setc(c) # 3. 迭代获取生成的结果 for v in scan() println(v) end
完整修改后的代码(适配新版JuMP)
顺便帮你把代码适配了新版JuMP的API(旧版的JuMP.solve、getvalue都已经废弃了):
using JuMP, Clp function scan_maker(A) m = JuMP.Model(Clp.Optimizer) # 用新版方式设置求解器参数 set_optimizer_attribute(m, "PrimalTolerance", 1e-3) set_optimizer_attribute(m, "DualTolerance", 1e-3) set_optimizer_attribute(m, "InfeasibleReturn", 1) set_optimizer_attribute(m, "PresolveType", 1) m_rows, level = size(A) v = zeros(Int, level) ub = zeros(Int, level) lb = zeros(Int, level) @variable(m, x[1:level]) @constraint(m, con, A*x .>= 0) function setc(c) @assert length(c) == m_rows "c的长度必须和约束数一致" for i in 1:m_rows set_normalized_rhs(con[i], c[i]) # 替代直接修改linconstr的不规范写法 end end function scan() return Channel() do ch i = 1 init = 1 while i > 0 if i >= init @objective(m, Max, x[i]) optimize!(m) res = termination_status(m) if res == OPTIMAL || res == UNBOUNDED x_val = value(x[i]) ub[i] = isinf(x_val) ? typemax(Int) : round(Int, x_val) @objective(m, Min, x[i]) optimize!(m) res = termination_status(m) @assert res == OPTIMAL || res == UNBOUNDED "变量$i的最小值求解失败" x_val_min = value(x[i]) lb[i] = isinf(x_val_min) ? typemin(Int) : round(Int, x_val_min) v[i] = lb[i] init += 1 else @assert res == INFEASIBLE "步骤i=$i时模型不可行" i -= 1 continue end elseif v[i] < ub[i] v[i] += 1 else set_upper_bound(x[i], Inf) set_lower_bound(x[i], -Inf) init -= 1 i -= 1 continue end if i >= level put!(ch, copy(v)) continue else set_upper_bound(x[i], v[i]) set_lower_bound(x[i], v[i]) i += 1 end end end end return setc, scan end # 调用示例 A = [1 2 3 4; 5 6 7 8] # 2x4非方阵 setc, scan = scan_maker(A) setc([1.0, 2.0]) for val in scan() println(val) end
内容的提问来源于stack exchange,提问作者Marouane1994
相关产品推荐
相关产品推荐

