Как использовать NLopt в Юлии с равенством - PullRequest
0 голосов
/ 03 сентября 2018

Я изо всех сил пытаюсь изменить Джулию-специфическое учебное пособие по NLopt , чтобы удовлетворить мои потребности, и был бы благодарен, если бы кто-то мог объяснить, что я делаю неправильно или не понимаю.

Я хочу:

  • Минимизировать значение некоторой целевой функции myfunc(x); где
  • x должен лежать в единичном гиперкубе (только 2 измерения в примере ниже); и
  • сумма элементов x должна быть равна единице.

Ниже я делаю myfunc очень простым - квадрат расстояния от x до [2.0, 0.0], так что очевидным правильным решением проблемы будет x = [1.0,0.0], для которого myfunc(x) = 1.0. Я также добавил println операторов, чтобы я мог видеть, что делает решатель.

testNLopt = function()

    origin = [2.0,0.0]
    n = length(origin)

    #Returns square of the distance between x and "origin", and amends grad in-place
    myfunc = function(x::Vector{Float64}, grad::Vector{Float64})
        if length(grad) > 0 
            grad = 2 .* (x .- origin)
        end
        xOut = sum((x .- origin).^2)
        println("myfunc: x = $x; myfunc(x) = $xOut; ∂myfunc/∂x = $grad")
        return(xOut)
    end

    #Constrain the sums of the x's to be 1...
    sumconstraint =function(x::Vector{Float64}, grad::Vector{Float64})
        if length(grad) > 0
            grad = ones(length(x)) 
        end
        xOut = sum(x) - 1
        println("sumconstraint: x = $x; constraint = $xOut; ∂constraint/∂x = $grad")
        return(xOut)
    end

    opt = Opt(:LD_SLSQP,n)

    lower_bounds!(opt, zeros(n))
    upper_bounds!(opt,ones(n))
    equality_constraint!(opt,sumconstraint,0)
    #xtol_rel!(opt,1e-4)
    xtol_abs!(opt,1e-8)

    min_objective!(opt, myfunc)
    maxeval!(opt,20)#to ensure code always terminates, remove this line when code working correctly?
    optimize(opt,ones(n)./n)
end

Я прочитал этот похожий вопрос и документацию здесь и здесь , но все еще не могу понять, что не так. К сожалению, каждый раз, когда я запускаю testNLopt, я вижу другое поведение , как на этом скриншоте , включая случаи, когда решатель бесполезно оценивает myfunc([NaN,NaN]) много раз.

1 Ответ

0 голосов
/ 03 сентября 2018

На самом деле вы не записываете параметры grad на месте, как вы пишете в комментариях;

grad = 2 .* (x .- origin)

просто переопределяет локальную переменную, а не содержимое массива - и я думаю, именно поэтому вы видите df/dx = [NaN, NaN] везде. Самый простой способ исправить это было бы с помощью широковещательной рассылки (обратите внимание на точку):

grad .= 2 .* (x .- origin)

и так далее. Вы можете прочитать об этом поведении здесь и здесь .

...