我正在寻找一种算法来优化地在球体表面上分布N个点(不是随机的,我说的是Tammes problem意义上的最佳分布)。 我想在C ++中这样做,但问题不是语言问题,而是算法问题。这是我目前使用的算法(在python中):
# Function to distribute N points on the surface of a sphere
# (source: http://www.softimageblog.com/archives/115)
def uniform_spherical_distribution(N):
pts = []
inc = math.pi * (3 - math.sqrt(5))
off = 2 / float(N)
for k in range(0, int(N)):
y = k * off - 1 + (off / 2)
r = math.sqrt(1 - y*y)
phi = k * inc
pts.append([math.cos(phi)*r, y, math.sin(phi)*r])
return pts
对于大量的点,视觉效果似乎相当不错,但是对于较少的点数(在2到10之间),结果看起来并不好(半球中的点数更多)。有没有办法增强算法,以便少数点...(答案可以是C,C ++或Python)。
答案 0 :(得分:1)
如果你需要的只是低点数,暴力可能会起作用。蛮力我的意思是预先计算2..10
的解决方案并在数组中查找{{1} }}
对于那样的小N<=10
,应该可以解决最佳地分配点的数学优化问题。你需要多步,但对于小N
s来说它应该不是问题。这是我在AMPL中的尝试:
N
在我的机器上运行此脚本花了5分钟,解决方案是:
N=2, min distance 2.000000 ( 1.000000, 0.000000, 0.000000) (-1.000000, 0.000000, 0.000000) N=3, min distance 1.732051 ( 1.000000, 0.000000, 0.000000) (-0.500000, 0.866025, 0.000000) (-0.500000, -0.866025, 0.000000) N=4, min distance 1.632993 ( 1.000000, 0.000000, 0.000000) (-0.333333, -0.942809, 0.000000) (-0.333333, 0.471405, -0.816497) (-0.333333, 0.471405, 0.816497) N=5, min distance 1.414214 ( 1.000000, 0.000000, 0.000000) (-0.208840, 0.977950, 0.000000) (-0.000000, 0.000000, 1.000000) (-0.212683, -0.977121, 0.000000) ( 0.000000, 0.000000, -1.000000) N=6, min distance 1.414214 ( 1.000000, 0.000000, 0.000000) (-1.000000, 0.000000, 0.000000) ( 0.000000, -0.752754, -0.658302) ( 0.000000, 0.752754, 0.658302) ( 0.000000, 0.658302, -0.752754) ( 0.000000, -0.658302, 0.752754) N=7, min distance 1.256870 ( 1.000000, 0.000000, 0.000000) (-0.688059, -0.725655, 0.000000) ( 0.210138, -0.488836, -0.846689) ( 0.210138, -0.488836, 0.846688) (-0.688059, 0.362827, 0.628435) (-0.688059, 0.362827, -0.628435) ( 0.210138, 0.977672, 0.000000) N=8, min distance 1.215563 ( 1.000000, 0.000000, 0.000000) ( 0.261204, -0.965284, 0.000000) ( 0.261204, 0.565450, 0.782329) (-0.783612, -0.482642, -0.391165) ( 0.261204, -0.199917, -0.944355) ( 0.261204, 0.882475, -0.391165) (-0.783612, 0.599750, 0.162026) (-0.477592, -0.399834, 0.782329) N=9, min distance 1.154701 ( 1.000000, 0.000000, 0.000000) (-0.500000, -0.866025, 0.000000) ( 0.333333, -0.577350, -0.745356) (-0.500000, 0.866025, 0.000000) (-0.666667, -0.000000, 0.745356) (-0.666667, 0.000000, -0.745356) ( 0.333333, -0.577350, 0.745356) ( 0.333333, 0.577350, -0.745356) ( 0.333333, 0.577350, 0.745356) N=10, min distance 1.091426 ( 1.000000, 0.000000, 0.000000) (-0.605995, 0.795469, 0.000000) ( 0.404394, 0.816443, 0.412172) (-0.664045, -0.746251, -0.046407) ( 0.404394, -0.363508, -0.839242) (-0.664045, 0.002497, 0.747688) (-0.605995, 0.046721, -0.794096) ( 0.404394, -0.908368, 0.106452) ( 0.255933, 0.703344, -0.663179) ( 0.404394, -0.159620, 0.900548)
通过查看数字,很明显可以通过分析计算某些解决方案(我认可sqrt(2)和sqrt(3)等)。我相信对于N = 2,4和6,解是直线([-1,0,0],[1,0,0]),四面体,八面体。
没有强保证以上是积分的最佳分配。非线性求解器可能陷入局部最优;随着param N;
var x{1..N};
var y{1..N};
var z{1..N};
var d;
param xbest{1..N};
param ybest{1..N};
param zbest{1..N};
param dbest;
maximize obj: d;
all_points_on_the_sphere{i in 1..N}:
x[i]^2 + y[i]^2 + z[i]^2 = 1;
all_pairs{i in 1..N, j in 1..N : i<j}:
(x[i]-x[j])^2 + (y[i]-y[j])^2 + (z[i]-z[j])^2 >= d;
fix_first_x: x[1] = 1;
fix_first_y: y[1] = 0;
fix_first_z: z[1] = 0;
fix_second_z: z[2] = 0;
#############################################
option show_stats 1;
option presolve 10;
option substout 1;
option var_bounds 2;
#option nl_comments 0;
#option nl_permute 0;
option display_precision 0;
option solver "/home/ali/ampl/ipopt";
for {k in 2..10} {
let N := k;
solexpand _con;
let dbest := -1.0;
# Multistart
for {1..2000} {
for {j in 1.._snvars}
let _svar[j] := Uniform(-1, 1);
let d := N;
solve;
if (solve_result_num < 200 and d > dbest) then {
let dbest := d;
for {i in 1..N} {
let xbest[i] := x[i];
let ybest[i] := y[i];
let zbest[i] := z[i];
}
}
}
print "@@@";
printf "N=%d, min distance %6f\n", N, sqrt(dbest);
for {i in 1..N}
printf "(%9.6f, %9.6f, %9.6f)\n", xbest[i], ybest[i], zbest[i];
}
的增长,局部最优的数量也会增加。
您可以将上述解决方案放在数组中,并在Python,C ++或您使用的任何语言中使用它们。