LsqFit.jl
LsqFit.jl copied to clipboard
InexactError when optimizing Complex-valued function
I'm trying to optimize a real-valued parameter to minimize a complex-valued least-squares problem.
Here's a MWE that demonstrates the problem. The basic idea is that you have a signal (x
) and a delayed version of that signal (x2
), and the object is to estimate the delay. We perform the delay in the frequency domain so that we can handle fractional-sample delays.
So the delay D
is what we're trying to optimize for, and the objective function is the least-squares difference (sum(abs2.(X2 - model(X)))
) in the spectra.
D_true = 1.35
x = [0; 1; zeros(14)]
X = rfft(x)
ω = range(0, π, length=9)
# delay x in the frequency domain
X2 = X .* exp.(-im * D_true .* ω)
x2 = irfft(X2, length(x))
function model(Xs, D)
X = @view Xs[:, 1]
ω = @view Xs[:, 2]
X .* exp.(-im * D[1] .* ω)
end
fit = curve_fit(model, [X ω], X2, [1.5])
Running curve_fit
gives an InexactError
- it looks like it's trying to assign a complex value into a real-valued array.
The reason for this is that in levenberg_marquardt.jl we require the value of the jacobian of the function-to-be-fitted. To compute it, we rely on OnceDifferentiable
from NLSolversBase.jl. When the jacobian isn't given by the user, OnceDifferentiable
will rely on finite_difference_jacobian!
from DiffEqTools. In this case it complains because the type of p0
differs from the type of [X ω]
and X2
.
If you try fit = curve_fit(model, [X ω], X2, [1.5+0im])
, you'll see that this error disappears, but...an another one comes up:
MethodError: no method matching OptimBase.MultivariateOptimizationResults(::LsqFit.LevenbergMarquardt, ::Array{Complex{Float64},1}, ::Array{Complex{Float64},1}, ::Float64, ::Int64, ::Bool, ::Bool, ::Float64, ::Float64, ::Bool, ::Float64, ::Float64, ::Bool, ::Float64, ::Float64, ::Bool, ::Array{OptimBase.OptimizationState{LsqFit.LevenbergMarquardt},1}, ::Int64, ::Int64, ::Int64)
Now, MultivariateOptimizationResults
is a struct from OptimBase.jl that LsqFit.jl
uses to store its results. Here it is complaining that the variables (so the parameters you want to optimize) have a different type (Complex{Float64}) than the type of the sum of residuals (Float64).
In order words, you should rather open a ticket in OptimBase.jl
:)
Thanks for the example. I'll keep it in mind when changing "optimization backend" in the near future.