LsqFit.jl icon indicating copy to clipboard operation
LsqFit.jl copied to clipboard

InexactError when optimizing Complex-valued function

Open ssfrr opened this issue 4 years ago • 4 comments

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.

ssfrr avatar Sep 24 '19 05:09 ssfrr

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.jluses 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 :)

Magalame avatar Nov 30 '19 06:11 Magalame

Thanks for the example. I'll keep it in mind when changing "optimization backend" in the near future.

pkofod avatar Jan 02 '20 13:01 pkofod