如何检查用户定义的函数是否已在Julia / JuMP中注册

时间:2016-08-04 18:00:03

标签: julia mathematical-optimization julia-jump

我想检查用户定义的函数是否已在JuMP / julia中注册。这是一个例子:

function foo( f, f1, f2 )

  if !function_is_registered(:f)  # This is what I'm looking for
    JuMP.register(:f,1,f1,f2)
  end
  ####
    # Optimization problem here using f
    # Leads to some return statement
  ####
end

f(x) = exp( A * x )
f1(x) = A * exp( A * x )
f2(x) = A * A * exp( A * x )
    # Function to register

A = 2
use1 = foo(f, f1, f2)
use2 = foo(f, f1, f2)
    # This second usage would fail without the check.  Can't re-register f.

从评论中可以明显看出,第二次使用时需要进行检查。据我所知,JuMP在全球范围内注册功能 - 一旦注册,就无法在本地重新定义(对吗?如果可以的话,这也解决了我的问题!)。

2 个答案:

答案 0 :(得分:2)

这将做你想要的。

using JuMP
using Ipopt

function set_A_sol( A )
  f = (x) -> exp( A * x ) - x
  f1 = (x) -> A * exp( A * x ) - 1.0
  f2 = (x) -> A * A * exp( A * x )
  # Local redefinition of f
  try
    JuMP.register(:f, 1, f, f1, f2)
  catch e
    if e.msg == "Operator f has already been defined"
      ind = pop!( ReverseDiffSparse.univariate_operator_to_id, :f);
      deleteat!( ReverseDiffSparse.univariate_operators, ind);
      pop!( ReverseDiffSparse.user_univariate_operator_f, ind);
      pop!( ReverseDiffSparse.user_univariate_operator_fprime, ind);
      pop!( ReverseDiffSparse.user_univariate_operator_fprimeprime, ind);
      JuMP.register(:f, 1, f, f1, f2);
    end
  end
  mod = Model(solver=Ipopt.IpoptSolver(print_level=0))
  @variable(mod, - Inf <= x <= Inf )
  @NLobjective(mod, Min, f(x) )
  status=solve(mod)
  return getvalue(x)
end

julia> ans1 = set_A_sol(0.5)
1.3862943611200509

julia> ans2 = set_A_sol(1.0)
0.0

julia> ans3 = set_A_sol(2.0)
-0.34657359027997264

说明:

如果查看nlp.jl中定义的寄存器功能,“注册”涉及将符号添加到ReverseDiffSparse中保存的字典中。 注册一个函数并手动检查这些词典,看看它们是什么样的。

所以“取消注册”只是从所有已经记录的地方删除所有痕迹:f及其衍生物。

答案 1 :(得分:0)

这是基于Tasos建议的扩展答案(感谢Tasos!)。

tl; dr 您可以对已注册的内容使用try-catch语句。您还可以在全局环境中更改目标函数中的参数,但不能将它们包装在函数中。

以下内容有效地允许检查函数的重新定义:

function foo2( f, f1, f2 )
  try
    JuMP.register(:f,1,f1,f2)
  end
  ####
  # Optimization problem here using f
  # Leads to some return statement
  ####
  end
end

更好的是,您实际上可以使用JuMP寻找f的天真方式来更改目标函数中的参数(尽管您每次都需要重新定义模型,因为您无法放置{{ 1}}在用户定义的目标中)。例如:

@NLparameter

您甚至可以将using JuMP using Ipopt f = (x) -> exp( A * x ) - x f1 = (x) -> A * exp( A * x ) - 1.0 f2 = (x) -> A * A * exp( A * x ) # Period objective function JuMP.register(:f, 1, f, f1, f2) A = 1.0 mod = Model(solver=Ipopt.IpoptSolver(print_level=0)) @variable(mod, - Inf <= x <= Inf ) @NLobjective(mod, Min, f(x) ) status=solve(mod) println("x = ", getvalue(x)) # Returns 0 A = 2.0 mod = Model(solver=Ipopt.IpoptSolver(print_level=0)) @variable(mod, - Inf <= x <= Inf ) @NLobjective(mod, Min, f(x) ) status=solve(mod) println("x = ", getvalue(x)) # Returns -0.34657 (correct) 重新定义为完全不同的内容,但仍然可以使用。但是,您无法将其包装在函数中。例如:

f

我不完全理解为什么,但似乎第一次在function set_A_sol( A ) f = (x) -> exp( A * x ) - x f1 = (x) -> A * exp( A * x ) - 1.0 f2 = (x) -> A * A * exp( A * x ) # Local redefinition of f try JuMP.register(:f, 1, f, f1, f2) end mod = Model(solver=Ipopt.IpoptSolver(print_level=0)) @variable(mod, - Inf <= x <= Inf ) @NLobjective(mod, Min, f(x) ) status=solve(mod) return getvalue(x) end ans1 = set_A_sol(0.5) ans2 = set_A_sol(1.0) ans3 = set_A_sol(2.0) # All return 1.38629 内设置了A,JuMP注册会一劳永逸地修复set_A_sol。鉴于这是我最终想要做的事情,我仍然被卡住了。建议欢迎!