如何将MultivariatePolynomials输出导入JuMP作为自定义函数?
解决MultivariatePolynomials多项式导入JuMP作为自定义函数的类型问题
问题分析
你碰到的MethodError核心原因确实和你推测的一样:c_11还是DynamicPolynomials.PolyVar类型的多项式对象,但JuMP的非线性表达式解析器只能识别数值或者JuMP自己定义的变量类型。直接在v11函数里返回多项式对象,JuMP没法把它转换成能处理的表达式结构,自然就触发了解析错误。
解决方案
我们需要把多项式转换成接受数值输入、输出数值结果的普通Julia函数,而不是直接返回多项式对象。这里有两种靠谱的实现方式:
方法1:用evaluate计算多项式数值
借助MultivariatePolynomials.evaluate方法,给多项式传入变量对应的数值,直接算出结果:
using JuMP, MultivariatePolynomials, Ipopt # 定义多项式变量 @polyvar k s 胃_1k 胃_2k 胃_3k 胃_4k 胃_5k 胃_6k 胃_7k 胃_8k 胃_9k 胃_10k 胃_11k 胃_12k 胃_13k E 蟻 # 补全你的自定义函数和多项式d的定义 d = ... # 你的d多项式定义 q11(a,b,c,d,e,f,g,h,i) = ... # 你的q11函数逻辑 f(s_val, 蟻_val, E_val) = ... # 你的f函数逻辑 # 完成替换得到目标多项式c_11 j_11 = subs(d, k=>q11(胃_1k,胃_2k,胃_3k,胃_4k,胃_5k,胃_6k,胃_7k,胃_8k,胃_9k), s=>f(s,蟻,E)) c_11 = subs(j_11, k=>-0.7071067811865476, s=>0) # 重新定义v11:把输入的数值映射到多项式变量,计算结果 function v11(胃_1k_val,胃_2k_val,胃_3k_val,胃_4k_val,胃_5k_val,胃_6k_val,胃_7k_val,胃_8k_val,胃_9k_val,胃_10k_val,胃_11k_val,胃_12k_val,胃_13k_val,蟻_val, E_val) # 构建变量到数值的映射字典 var_map = Dict( 胃_1k => 胃_1k_val, 胃_2k => 胃_2k_val, 胃_3k => 胃_3k_val, 胃_4k => 胃_4k_val, 胃_5k => 胃_5k_val, 胃_6k => 胃_6k_val, 胃_7k => 胃_7k_val, 胃_8k => 胃_8k_val, 胃_9k => 胃_9k_val, 胃_10k => 胃_10k_val, 胃_11k => 胃_11k_val, 胃_12k => 胃_12k_val, 胃_13k => 胃_13k_val, 蟻 => 蟻_val, E => E_val ) # 计算多项式在给定数值下的结果 return evaluate(c_11, var_map) end # 创建模型并注册函数 m = Model(solver=IpoptSolver()) # 注意:注册时的参数个数要和v11的输入数量一致(你之前写的27是错的,实际是15个) JuMP.register(m, :v11, 15, v11, autodiff=true) # 必须先定义JuMP变量!之前的代码漏掉了这一步 @variable(m, 胃_1k) @variable(m, 胃_2k) @variable(m, 胃_3k) @variable(m, 胃_4k) @variable(m, 胃_5k) @variable(m, 胃_6k) @variable(m, 胃_7k) @variable(m, 胃_8k) @variable(m, 胃_9k) @variable(m, 胃_10k) @variable(m, 胃_11k) @variable(m, 胃_12k) @variable(m, 胃_13k) @variable(m, 蟻) @variable(m, E) @variable(m, w_1) @variable(m, 尾) @variable(m, 未) # 补全约束表达式后添加 @NLconstraint(m, cons1, v11(胃_1k,胃_2k,胃_3k,胃_4k,胃_5k,胃_6k,胃_7k,胃_8k,胃_9k,胃_10k,胃_11k,胃_12k,胃_13k,蟻, E) * w_1 + 尾*(1-未) == ...) # 求解模型 status = solve(m)
方法2:编译多项式为Julia函数
用MultivariatePolynomials.build_function直接把多项式转换成高效的原生Julia函数,性能会更好:
# 在得到c_11之后,生成函数代码和对应的变量列表 func, vars = build_function(c_11, [胃_1k,胃_2k,胃_3k,胃_4k,胃_5k,胃_6k,胃_7k,胃_8k,胃_9k,胃_10k,胃_11k,胃_12k,胃_13k,蟻, E]) # 生成可直接调用的函数 v11 = eval(func) # 后续的模型注册、变量定义、约束添加和方法1完全一致 JuMP.register(m, :v11, 15, v11, autodiff=true)
额外注意点
- 参数个数必须匹配:你之前
register里写的27是错误的,v11实际只有15个输入参数,不匹配会触发其他错误。 - 必须定义JuMP变量:JuMP的约束只能用它自己通过
@variable定义的变量类型,不能直接用多项式变量,之前的代码漏掉了这关键一步。 - 自动微分兼容性:两种方法都支持
autodiff=true,因为evaluate和编译后的函数都是可导的,JuMP能正常处理自动微分。
内容的提问来源于stack exchange,提问作者ludo
相关产品推荐
相关产品推荐

