This is a perfect use case for defining your own (mutable) struct to hold the factorization. For example, you can simply do:
mutable struct MyFactorization
J
needs_update::Bool
end
This struct is mutable, so you can pass it into a function and do:
function foo(fact::MyFactorization, x)
if fact.needs_update
fact.J = factorize(Jacobian(x))
fact.needs_update = false
end
end
Any mutation of fact
inside the function will be visible to anywhere else you have that same fact
object. So if you do:
fact = MyFactorization(...whatever...)
foo(fact, x)
@show fact.J
then you’ll see that fact.J
will have been updated. This avoids any global variables and means you could even have multiple factorization objects, should you need that in the future.
For better performance, you can annotate the type of J
in your struct:
mutable struct MyFactorization
J::LinAlg.LU{Float64,Array{Float64,2}} # I'm guessing here, your type may be different
needs_update::Bool
end
Or for better performance and more flexibility, you can make that type a parameter, and Julia will figure it out for you:
mutable struct MyFactorization{T}
J::T
needs_update::Bool
end
Even better, once you’ve done this, you can make some convenient functions, like:
function factors(f::MyFactorization, x)
if f.needs_update
f.J = factorize(Jacobian(x))
f.needs_update = false
end
return f.J
end
and now you can simply call factors(f, x)
everywhere and it will just do the right thing, only updating the factorization as necessary.
On a side note, I thought it would be pretty neat if appending a ! at the end of a function was not just a convention, but added the property that any argument that is modified within the function is modified outside.
That would be interesting, but it doesn’t really fit into the way variables are passed in Julia (it’s more like what’s done with references in C++), and it would spectacularly break a lot of existing code, so it’s not likely to happen any time soon