我正在使用Python/numpy/scipy编写一个小型的光线跟踪器。表面被建模为二维函数,其给出相对于法平面的高度。我将射线与表面的交点问题简化为找到一个单变量函数的根。这些函数是连续可微的。
有没有比简单遍历所有函数更有效的方法,可以使用scipy根查找器(可能还要使用多个进程)?
编辑:这些函数是表示射线和表面函数之间差异的函数,受到交点平面的限制。
我正在使用Python/numpy/scipy编写一个小型的光线跟踪器。表面被建模为二维函数,其给出相对于法平面的高度。我将射线与表面的交点问题简化为找到一个单变量函数的根。这些函数是连续可微的。
有没有比简单遍历所有函数更有效的方法,可以使用scipy根查找器(可能还要使用多个进程)?
编辑:这些函数是表示射线和表面函数之间差异的函数,受到交点平面的限制。
import numpy
def F(x, a, b):
return numpy.power(x, a+1.0) - b
N = 1000000
a = numpy.random.rand(N)
b = numpy.random.rand(N)
x0 = numpy.zeros(N)
x1 = numpy.ones(N) * 1000.0
max_step = 100
for step in range(max_step):
x_mid = (x0 + x1)/2.0
F0 = F(x0, a, b)
F1 = F(x1, a, b)
F_mid = F(x_mid, a, b)
x0 = numpy.where( numpy.sign(F_mid) == numpy.sign(F0), x_mid, x0 )
x1 = numpy.where( numpy.sign(F_mid) == numpy.sign(F1), x_mid, x1 )
error_max = numpy.amax(numpy.abs(x1 - x0))
print "step=%d error max=%f" % (step, error_max)
if error_max < 1e-6: break
...
F0 = F(x0, a, b)
F1 = F(x1, a, b)
max_step = 100
for step in range(max_step):
x_mid = (x0 + x1)/2.0
F_mid = F(x_mid, a, b)
mask0 = numpy.sign(F_mid) == numpy.sign(F0)
mask1 = numpy.sign(F_mid) == numpy.sign(F1)
x0 = numpy.where( mask0, x_mid, x0 )
x1 = numpy.where( mask1, x_mid, x1 )
F0 = numpy.where( mask0, F_mid, F0 )
F1 = numpy.where( mask1, F_mid, F1 )
...
相比之下,使用scipy.bisect()逐个查找根需要约94秒:
for i in range(N):
x_root = scipy.optimize.bisect(lambda x: F(x, a[i], b[i]), x0[i], x1[i], xtol=1e-6)
scipy.optimize.newton
获得了矢量化支持。使用另一个答案中的示例现在看起来像这样:import numpy as np
from scipy import optimize
def F(x, a, b):
return np.power(x, a+1.0) - b
N = 1000000
a = np.random.rand(N)
b = np.random.rand(N)
optimize.newton(F, np.zeros(N), args=(a, b))
这个方法的运行速度和其他答案中向量化二分法一样快。