我有一个(不可逆)函数 ak([u,v,w])
这将获取单位八面体表面上的一个点(p:使得 |u|+|v|+|w| = 1)并返回单位球体表面上的一个点。该函数并不完美,但目的是保持点之间的距离为等积。
我正在考虑使用 SciPy 最小化来提供数值逆,但我无法理解它。
输入:球面 pt [x,y,z],
输出八面体 pts [u,v,w],使得 ak([u,v,w])=[x,y,z]
我的函数 ak() 定义如下:
def ak(p):
# Convert point on octahedron onto the sphere.
# Credit to Anders Kaseorg: https://math.stackexchange.com/questions/5016695/
# input: oct_pt is a Euclidean point on the surface of a unit octagon.
# output: UVW on a unit sphere.
a = 3.227806237143884260376580641604959964752197265625 # 𝛂 - vis. Kaseorg.
p1 = (np.pi * p) / 2.0
tp1 = np.tan(p1)
xu, xv, xw = tp1[0], tp1[1], tp1[2]
u2, v2, w2 = xu ** 2, xv ** 2, xw ** 2
y0p = xu * (v2 + w2 + a * w2 * v2) ** 0.25
y1p = xv * (u2 + w2 + a * u2 * w2) ** 0.25
y2p = xw * (u2 + v2 + a * u2 * v2) ** 0.25
pv = np.array([y0p, y1p, y2p])
return pv / np.linalg.norm(pv, keepdims=True)
此函数基于我在 Math StackExchange 上发表的一篇文章。
有什么提示吗?
我发现一个很有帮助的想法是将其从最小化问题转换为求根问题。
根查找器不支持约束,因此您需要更改目标函数以强制 x 在转换为笛卡尔坐标之前进行 L1 归一化。
一旦你这样做了,你就可以找到 的点
ak(op / norm) - tx = 0
。(我还将八面体表面中心的初始猜测改为
np.arcsin(tsp) / (np.pi / 2)
。我发现这减少了收敛所需的时间。)我发现这将当前解决方案的误差减少了约 10^7 倍,同时对 ak() 的调用次数比之前的解决方案要少。
完整测试代码
注意:参数 𝛂 的位数比实际需要的多得多。当 Python 对这个数字进行数学运算时,它会忽略双精度浮点数中所有不适合的数字,这意味着该数字在内部被转换为 3.2278062371438843。
尝试过其他方法
我还尝试使用 SymPy 为该函数提出解析雅可比矩阵,但在自动微分方面遇到了太多麻烦。如果你能找到这个,你就能更快、更准确地微分该函数。
我也尝试了基于的解决方案
scipy.interpolate.RbfInterpolator
。它获得了与最小化方法类似的准确性和速度。@Reinderian 指出我可以使用代码审查,但当我撰写问题时,我没有什么可审查的。我担心交叉发布,所以将这个问题留在这里。
@nick-odell 的回答特别有用- 我全心全意地采纳了他的想法。
以下答案是对原始答案的更新(我将其留在下面,特别是因为 Nick 对此进行了评论)
这主要遵循了 Nick 的代码,但添加了他建议的雅可比矩阵,所以我想他(或对这个领域感兴趣的人)可能想看看我到了哪里。@Nick,我很担心你泄露了许多潜艇的位置 - 虽然其中一艘肯定被困在加拿大努纳武特的一个小湖里。
GCD(经度/纬度)的往返误差远低于 1µm,这比我所希望的要令人印象深刻得多。
Nick 对 initial_guess 的建议似乎在使用 N=1e+5(相同种子)时失去了可行性,而我用它替换了,
np.sign(tsp) * 1./3.
它调用次数更少,而且看起来更稳定jac
。容差设置为 1e-12 时,N=1e+5 的最大误差为 0.75µm,三次计算需要调用 32 次才能收敛。
将容差修改为 1e-15 可达到 4nm,最多需要调用 41 次才能收敛。
我将例程放入 (静态) 类中,以便整洁,也因为我很难
jac
正确调用该函数。另外,sympy 雅可比分析速度不快,所以最好只生成一次。GeographicLib
为了获得可靠的距离度量,已导入Charles Karney 的距离度量 - 这是 (几乎) 每个 GIS 库使用的底层测地线系统。它仅用于测量精度。向 Nick 和 Anders 表示感谢和敬意。
我通常对单位八面体和单位球体之间的等积(或近等积)投影感兴趣 - 尤其是在三角网格上,尤其是那些看起来很舒服并且与等边三角形偏差不大的投影(不用说,我知道球体投影的顶点角为 90º,而在八面体上为 60º)。我同样对代码的改进(速度、准确性、效率)感兴趣。
先前的答案
并且输出...