我有一个矩阵(实际上是一个加载的图像),其中每个元素都是距离某个未知中心点的L2距离。
这是一个简单的例子
A = [1.4142 1.0000 1.4142 2.2361]
[1.0000 0.0000 1.0000 2.0000]
[1.4142 1.0000 1.4142 2.2361]
在这种情况下,中心显然位于坐标(1,1)(0索引矩阵或2D数组中的索引A [1,1])。
然而,在我的中心不被限制为整数指数的情况下,它不再那么明显。例如,给定此矩阵B
,我的中心坐标在哪里?
B = [3.0292 1.9612 2.8932 5.8252]
[1.2292 0.1612 1.0932 4.0252]
[1.4292 0.3612 1.2932 4.2252]
在这种情况下,您如何找到答案是在行1.034和第1.4列?
我知道trilateration解决方案(有provided MATLAB code to visualize that in 3D previously),但是有更有效的方法(例如没有矩阵倒置的方法)吗?
这个问题与语言无关,因为我正在寻找更多的算法帮助。如果您在解决方案中坚持使用MATLAB,Python或C ++,那就太棒了; - )。
答案 0 :(得分:1)
虽然没有类似任务的经验,但我读了一些东西并尝试了一些东西。
当不熟悉这个主题时,很难理解它,我发现的所有资源都有点混乱。
关于我的理论还不清楚:
这里有一些示例代码,有两种方法:
其他一些评论:
<强>代码:强>
import numpy as np
import cvxpy as cvx
from scipy.spatial.distance import cdist
from scipy.optimize import minimize
np.random.seed(1)
""" Create noise-free (not anymore!) fake-problem """
real_x = np.random.random(size=2) * 3
M, N = 5, 10
NOISE_DISTS = 0.1
pos = np.array([(i,j) for i in range(M) for j in range(N)]) # ugly -> tile/repeat/stack
real_x_stacked = np.vstack([real_x for i in range(pos.shape[0])])
Y = cdist(pos, real_x[np.newaxis])
Y += np.random.normal(size=Y.shape)*NOISE_DISTS # Let's add some noise!
print('-----')
print('PROBLEM')
print('-------')
print('real x: ', real_x)
print('dist mat: ', np.round(Y,3).T)
""" Helper """
def cost(x, Y, pos):
res = np.linalg.norm(pos - x, ord=2, axis=1) - Y.ravel()
return np.linalg.norm(res, 2)
print('cost with real_x (check vs. noisy): ', cost(real_x, Y, pos))
""" SOLVER SOCP """
def solve_socp_relax(pos, Y):
x = cvx.Variable(2)
y = cvx.Variable(pos.shape[0])
fake_stack = [x for i in range(pos.shape[0])] # hacky
objective = cvx.sum_entries(cvx.norm(y - Y))
x_stacked = cvx.reshape(cvx.vstack(*fake_stack), pos.shape[0], 2) # hacky
constraints = [cvx.norm(pos - x_stacked, 2, axis=1) <= y]
problem = cvx.Problem(cvx.Minimize(objective), constraints)
problem.solve(solver=cvx.ECOS, verbose=False)
return x.value.T
""" SOLVER NLP """
def solve_nlp(pos, Y):
sol = minimize(cost, np.zeros(pos.shape[1]), args=(Y, pos), method='BFGS')
# print(sol)
return sol.x
""" TEST """
print('-----')
print('SOLVE')
print('-----')
socp_relax_sol = solve_socp_relax(pos, Y)
print('SOCP RELAX SOL: ', socp_relax_sol)
nlp_sol = solve_nlp(pos, Y)
print('NLP SOL: ', nlp_sol)
<强>输出:强>
-----
PROBLEM
-------
real x: [ 1.25106601 2.16097348]
dist mat: [[ 2.444 1.599 1.348 1.276 2.399 3.026 4.07 4.973 6.118 6.746
2.143 1.149 0.412 0.766 1.839 2.762 3.851 4.904 5.734 6.958
2.377 1.432 0.856 1.056 1.973 2.843 3.885 4.95 5.818 6.84
2.711 2.015 1.689 1.939 2.426 3.358 4.385 5.22 6.076 6.97
3.422 3.153 2.759 2.81 3.326 4.162 4.734 5.627 6.484 7.336]]
cost with real_x (check vs. noisy): 0.665125233772
-----
SOLVE
-----
SOCP RELAX SOL: [[ 1.95749275 2.00607253]]
NLP SOL: [ 1.23560791 2.16756168]
编辑:使用非线性最小二乘法代替更一般的NLP方法,可以实现进一步的加速(特别是大规模)!我的结果仍然相同(如果问题是凸的,可以预期)。 NLP / NLS之间的时间可能看起来像9对0.5秒!
这是我推荐的方法!
def solve_nls(pos, Y):
def res(x, Y, pos):
return np.linalg.norm(pos - x, ord=2, axis=1) - Y.ravel()
sol = least_squares(res, np.zeros(pos.shape[1]), args=(Y, pos), method='lm')
# print(sol)
return sol.x
特别是第二种方法(NLP)也将运行更大的实例(cvxpy的开销伤害;这不是SOCP解算器的缺点,它应该扩展得更好!)。
此处M, N = 500, 1000
的一些输出带有更多噪音:
-----
PROBLEM
-------
real x: [ 12.51066014 21.6097348 ]
dist mat: [[ 24.706 23.573 23.693 ..., 1090.29 1091.216
1090.817]]
cost with real_x (check vs. noisy): 353.354267797
-----
SOLVE
-----
NLP SOL: [ 12.51082419 21.60911561]
used: 5.9552763315495625 # SECONDS
所以在我的实验中它起作用,但我不会给出任何全局收敛保证或重建保证(仍然缺少一些理论)。
起初我虽然使用轻松SOCP问题的全局最优作为NLP求解器的初始点,但我没有找到任何需要它的例子!
一些有趣的视觉效果使用:
M, N = 20, 30
NOISE_DISTS = 0.2
...
import matplotlib.pyplot as plt
plt.imshow(Y.reshape(M, N), cmap='viridis', interpolation='none')
plt.colorbar()
plt.scatter(nlp_sol[1], nlp_sol[0], color='red', s=20)
plt.xlim((0, N))
plt.ylim((0, M))
plt.show()
还有一些超级嘈杂的表壳(表现不错!):
M, N = 50, 100
NOISE_DISTS = 5
-----
PROBLEM
-------
real x: [ 12.51066014 21.6097348 ]
dist mat: [[ 22.329 18.745 27.588 ..., 94.967 80.034 91.206]]
cost with real_x (check vs. noisy): 354.527196716
-----
SOLVE
-----
NLP SOL: [ 12.44158986 21.50164637]
used: 0.01050068340320306
答案 1 :(得分:0)
如果我理解正确,你有一个矩阵A,其中A [i,j]保持从(i,j)到某个未知点(y,x)的距离。你可以这样找到(y,x):
对A的每个元素进行平方,使矩阵B说出来。 然后我们想找到(y,x)所以
(y-i)*(y-i) + (x-j)*(x-j) = B[i,j]
从0,0等式中减去每个等式并重新排列:
2*i*y + 2*j*x = B[0,0] + i*i + j*j - B[i,j]
这可以通过线性最小二乘法来解决。请注意,由于存在2个未知数,因此涉及的matix反转(更好,因子分解)将位于2x2矩阵上,因此不会耗费时间。实际上,只要给出A的维数,就可以解析出所需的矩阵及其逆矩阵。