Zygote error when using Nonconvex.jl: Mutating arrays is not supported

Hi all,

I am new to Julia and trying to use SLSQP Nonconvex. The optimization code is as follows:

using Nonconvex
Nonconvex.@load NLopt

start_vec = zeros(11)
gamma_vec = range(start=-7, stop=7, length=40)
rho = 0.58
t_vec = range(0.0,5.0)
alpha = 0.05
d = 6.0
no_nodes_GL = 20
lambda = 0.1
num_ints = 20

obj_fun(x) = OBJ_ciuupi(x, lambda, t_vec, d, alpha, no_nodes_GL)
con_func(x) = constr_func_ciuupi(x, t_vec, d, alpha, rho, gamma_vec, no_nodes_GL, num_ints)

alg = NLoptAlg(:LD_SLSQP)
options = NLoptOptions()
model = Model(obj_fun)
addvar!(model, fill(-Inf, length(start_vec)), fill(Inf, length(start_vec)))
add_ineq_constraint!(model, con_func)
r = Nonconvex.optimize(model, alg, start_vec, options = options)

But it produces the error

ERROR: Mutating arrays is not supported -- called setindex!(Vector{Float64}, ...)
This error occurs when you ask Zygote to differentiate operations that change
the elements of arrays in place (e.g. setting values with x .= ...)

Possible fixes:
- avoid mutating operations (preferred)
- or read the documentation and solutions for this error
  https://fluxml.ai/Zygote.jl/latest/limitations

Stacktrace:
  [1] error(s::String)
    @ Base .\error.jl:35
  [2] _throw_mutation_error(f::Function, args::Vector{Float64})
    @ Zygote C:\Users\gperera@ltu.edu.au\.julia\packages\Zygote\YYT6v\src\lib\array.jl:70
  [3] (::Zygote.var"#539#540"{Vector{Float64}})(#unused#::Nothing)
    @ Zygote C:\Users\gperera@ltu.edu.au\.julia\packages\Zygote\YYT6v\src\lib\array.jl:82
  [4] (::Zygote.var"#2627#back#541"{Zygote.var"#539#540"{Vector{Float64}}})(Δ::Nothing)
    @ Zygote C:\Users\gperera@ltu.edu.au\.julia\packages\ZygoteRules\4nXuu\src\adjoint.jl:71
  [5] Pullback
    @ c:\Users\gperera@ltu.edu.au\OneDrive - LA TROBE UNIVERSITY\RESEARCH\ciuupi.sinc\29Nov2023 (Didnt work)\Julia\s_x.jl:39 [inlined]

The s_x function the error is pointing at is as follows.

function s_x(t, s_knots_vec, t_vec, alpha, d)
    # 
    # 
    #
    # 
    #
    # 
    # 
    # 
    # 
    # 
    # 
    # 
    #
    # 
    # 
    # 
    # 
    # 
    # 
    #
    # 
    # 
    
    z = Distributions.quantile(Normal(), 1 - alpha/2)

    if(abs(t)>=d)
        return z
    end

    len_t_vec = length(t_vec)

    s_t_vec = zeros(len_t_vec)
    s_t_vec[1]=sinc_fun(t/(d/len_t_vec))

    for j in 2:len_t_vec
        i=t_vec[j]
        s_t_vec[j]=(sinc_fun((t+i)/(d/length(t_vec))) + sinc_fun((t-i)/(d/length(t_vec))))
    end

    s_c = sum(s_knots_vec .*s_t_vec)
    s_t = z + s_c
    return s_t
end

Can someone please help me with this error

The SLSQP algorithm requires you to supply the gradient of your objective function. Since you didn’t supply this, Nonconvex.jl is helpfully trying to compute the gradient automatically using automatic differentiation (AD) via the Zygote.jl package.

Unfortunately, Zygote.jl cannot differentiate functions that contain “mutation”, which means changing (“mutating”) array elements via statements like s_t_vec[j] = ....

You can either compute your gradient manually, rewrite your function into a more “functional” style that Zygote.jl can differentiate, try another AD system like Enzyme.jl or ForwardDiff.jl that supports mutation, or use an optimization algorithm that does not require derivatives.

2 Likes

Also see this section in the docs for supplying gradients or using other AD packages which might be more compatible with your functions.

2 Likes