如何计算 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]
此外,这个解决方案实际上确实在线条之外进行了推断。我没有找到根据参数更改拟合范围的方法。
所以您需要采取的步骤是:
- 找到
dx
的范围,确保曲线至少重叠 50%
- 定义两条曲线,将它们命名为
f
和 g
,使用 interpolate
(没有 extrapolate
)来自 Interpolations.jl 使用您拥有的点
- 定义一个函数来计算它们之间的总距离;最简单的方法是将 QuadGK.jl 与基于
dx
的积分范围和曲线范围一起使用(以便我们在不进行外推的情况下积分,将此范围的末端称为 xmin
和 xmax
): quadgk(x -> (f(x)-g(x+dy)+dy)^2, xmin, xmax))
;使其成为 dx
和 dy
的函数
- 然后使用例如Optim.jl 找到最优的
dx
和 dy
(对 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)
我有两个函数,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]
此外,这个解决方案实际上确实在线条之外进行了推断。我没有找到根据参数更改拟合范围的方法。
所以您需要采取的步骤是:
- 找到
dx
的范围,确保曲线至少重叠 50% - 定义两条曲线,将它们命名为
f
和g
,使用interpolate
(没有extrapolate
)来自 Interpolations.jl 使用您拥有的点 - 定义一个函数来计算它们之间的总距离;最简单的方法是将 QuadGK.jl 与基于
dx
的积分范围和曲线范围一起使用(以便我们在不进行外推的情况下积分,将此范围的末端称为xmin
和xmax
):quadgk(x -> (f(x)-g(x+dy)+dy)^2, xmin, xmax))
;使其成为dx
和dy
的函数
- 然后使用例如Optim.jl 找到最优的
dx
和dy
(对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)