Как проверить, что пользовательская функция уже зарегистрирована в 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 регистрирует функции на глобальном уровне - после регистрации они не могут быть переопределены локально (верно? Если они могут, это решает и мою проблему!).


person squipbar    schedule 04.08.2016    source источник


Ответы (1)


Вот расширенный ответ, основанный на предложениях Тасоса (спасибо, Тасос!).

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 раз и навсегда. Учитывая, что это то, что я в конечном итоге хочу делать, я все еще застрял. Предложения приветствуются!

person squipbar    schedule 05.08.2016