1

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.

コメントから明らかなように、2 回目の使用にはチェックが必要です。私が知る限り、JuMP は関数をグローバル レベルで登録します。一度登録すると、ローカルで再定義することはできません (そうですよね? 可能であれば、これで私の問題も解決します!)。

4

2 に答える 2

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 で定義されている register 関数を見ると、「登録」には、ReverseDiffSparse に保持されている辞書へのシンボルの追加が含まれます。関数を登録し、それらの辞書を手動でチェックして、それらがどのように見えるかを確認します。

したがって、「登録解除」とは、記録されたすべての場所から :f とその派生物のすべての痕跡を削除することです。

于 2016-08-06T00:34:46.167 に答える
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(ただし、ユーザー定義の目的関数に を入れることはできないため、毎回モデルを再定義する必要があります@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が内部に設定されるset_A_solと、JuMP の登録が完全に修正Aされるようです。これが私が最終的にできるようにしたいことであることを考えると、私はまだ立ち往生しています。提案を歓迎します!

于 2016-08-05T20:09:12.337 に答える