如何计算 Julia 中两条线(2 坐标点的序列)之间的距离

How to compute distance between two lines (sequence of 2-coordinate points) in Julia

我有两个函数,y = f(x)y = g(x),通过 Array{Float64,2} 定义——一系列 (x, y) 点。

我想找到图表上函数之间的距离最小的 f'(x) = f(x+dx) + dy。比如这里,距离已经很小了,还可以更小

在我的特殊情况下,两个数组中的点数相同,因此我尝试最小化以下函数(假设 p = [dx, dy]):

loss(p) = sum(abs2, mapslices(x -> x .- p, f .- g, dims=2))

但是,显然,这并不奏效。另外,如果能够处理不同大小的数组就好了。

我想到的一个解决方案(不确定它的最优程度):

using Interpolations, LsqFit

etp = extrapolate(interpolate((fx,), fy, Gridded(Linear())), Line())

model(x, p) = collect(map(i -> etp[i], x.+p[1])).+p[2]

fit = curve_fit(model, gx, gy, [0.0, 0.0])
res = coef(fit) # outputs an array like [dx, dy]

此外,这个解决方案实际上确实在线条之外进行了推断。我没有找到根据参数更改拟合范围的方法。

所以您需要采取的步骤是:

  1. 找到 dx 的范围,确保曲线至少重叠 50%
  2. 定义两条曲线,将它们命名为 fg,使用 interpolate(没有 extrapolate)来自 Interpolations.jl 使用您拥有的点
  3. 定义一个函数来计算它们之间的总距离;最简单的方法是将 QuadGK.jl 与基于 dx 的积分范围和曲线范围一起使用(以便我们在不进行外推的情况下积分,将此范围的末端称为 xminxmax): quadgk(x -> (f(x)-g(x+dy)+dy)^2, xmin, xmax));使其成为 dxdy
  4. 的函数
  5. 然后使用例如Optim.jl 找到最优的 dxdy(对 dx 有约束)

@leventov,我考虑过使用 Optim 的这个解决方案,它最小化沿一条曲线的矢量与第二条曲线的最小距离。允许任意数组长度,不需要 interpolate/extrapolate.

using Optim, LinearAlgebra, Plots, Printf

function costf(x0)
    n, m = length(x1), length(x2)
    d = fill(Inf,n,1)
    for (ux, uy, i) in zip(x1, y1, 1:n)
        for (vx, vy) in zip(x2, y2)
            dij = norm([ux - vx - x0[1], uy - vy - x0[2]])
            dij < d[i] ? d[i] = dij : nothing
        end
    end
    return sum(d .^0.5)   # better metric for this problem
end

# x1, y1 = [-2.; -1; 0; 1; 2; 3], [4.; 1; 0; 1; 4; 9]
# x2, y2 = [0.; 0.5; 1; 2; 1], [0.; -0.75; -1; 0; 3]
x1 = -2:0.1:2;  y1 = x1 .^2
z = [exp(im*i/36*2pi) for i in 0:36]
x2, y2 = pi .+ 0.5*real(z), exp(1) .+ 0.5*(1.0 .+ imag(z))
x0 = [-2.0, -1.0]
res = optimize(costf, x0)
x0 = Optim.minimizer(res)

str = "Optim shift: dx= " * @sprintf("%.2f",x0[1]) * ", dy= " * @sprintf("%.2f",x0[2])
plot(x1,y1, color=:cyan, labels= "Input curve-1", legend=:topleft, aspectratio=1)
plot!(x2,y2, color=:blue, labels= "Input curve-2")
plot!(x2 .+ x0[1], y2 .+ x0[2], color=:red, labels= str)