Change variable outside of local scope

Hi everyone,

I try to solve a model and would like to update the parameters of the model with each iteration.

For instance, I have a function like this:

function solve_GE(par::Pars)
    res = zeros(2)
    f!(x) = residuals_GE(x, res; par)
    initial_x = [1., 1.]
    sol = nlsolve(f!, initial_x)
    return sol
end

The function residuals_GE takes two parameters, updates the struct par, and solves the model given the parameters. Afterward, two residuals are computed that follow from the model’s solution.

My question is whether I can keep the struct par that was computed inside residuals_GE and reuse it? Intuitively, the previous solution to the model should be closer to the next iteration than the solution that I fed into the model in the very beginning.

Thanks for any pointers!

I think we cannot answer this without knowing more. residuals_GE is not called directly inside solve_GE but (I assume) it is called inside nlsolve. If par is mutable struct and residuals_GE changes par, then these changes will reflect wherever you have the par object stored (i.e., you are already updating the parameters). However, if par is immutable (plain struct), or residuals_GE do not mutate it, then things complicate. In this case, if residuals_GE do not mutate the old par neither return an updated par, then there is nothing to do. The new par value do not escape residuals_GE. If it returns an updated copy, then nlsolve would need to be able to deal with this extra return and keep the last par returned by f! to return it too.

1 Like

Thank you for your reply and your understanding is accurate. I was using par as an immutable struct combined with the package Setfield.jl to update variables that are related to the solution. However, using @set! par.x = new_x withing residuals_GE did not actually affect par.x for the next iteration run through nlsolve!. Then I tried declaring par as a mutable struct and instead used par.x = new_x, which indeed updated the field for the next iteration run through nlsolve!. Thanks!

Only question: Is that difference in behavior expected between immutable struct + Setfield or mutable struct + direct assignment or is that a bug?

That’s expected. Setfield will create a new struct with a changed field, it cannot modify the original struct – you declared that to be immutable after all.

2 Likes

Thanks for the great explanation! Did not think much about how Setfield works, just thought immutable plus Setfield makes it less likely that I mess with the struct by accident.