*如果你在huji做intro2cs要小心...... 我知道你为什么在这里*
我正在尝试构建一个函数来获取函数(假设单调的连续性)作为参数并返回其反函数。
从数学我知道我需要将函数反映到y=x
。
但这并不是很顺利。
我写了一些内容,会给我x0
f(x0)=0
。
def solve(f, x0=-10000, x1=10000, epsilon=EPSILON):
"""return the solution to f in the range between x0 and x1"""
while x1-x0>EPSILON:
if (f(x0)*f((x1+x0)/2))<0:
x1=((x1+x0)/2)
elif (f(x0)*f((x1+x0)/2))>0:
x0=((x1+x0)/2)
elif (f(x0)*f(x1))==0:
if f(x0)==0:
return x0
else:
return x1
if f(x0)*f(x1)<0:
return (x1+x0)/2
else:
return None
问题是我不知道该功能的范围输入是什么。 我想我首先需要在小范围上工作,如果我找不到解决方案,我会以指数方式扩展范围。
有什么想法吗?
更新:
好的,所以我试着把它写成@Spektre
建议,然后我成功了:
def inverse(g, epsilon=EPSILON):
"""return f s.t. f(g(x)) = x"""
def helper(y):
x0=-2
x1=2
while x1<10000:
if solve((lambda x:g(x)-y),x0,x1,epsilon):
return solve((lambda x:g(x)-y),x0,x1,epsilon)
else:
x0=math.pow(x0,3)
x1=math.pow(x1,3)
return helper
答案 0 :(得分:1)
没有y=f(x)
无法知道实际的x
或y
间隔。
正如您所提到的,您只需要连续且单调的间隔
所以,如果你不知道它你可以尝试找到极值点(第一个推导交叉为零),一些搜索动态步骤依赖于推导值(线性或对数)但是总会有丢失的风险小颠簸。如果您创建这些点的列表,那么它们之间的间隔应该是单调的。在此之后如果x=g(y)
功能正常,您可以使用二进制搜索。如果存在小凸起,那么approximation search会更好。
对于未绑定的单调函数y=f(x)
您可以将上面链接中的近似搜索更改为以下内容:
初步猜测
x0=0
如果没有关于g,f
的更多信息,我们无能为力。如果x0=0
不是选项,请使用任何其他安全值。
检测搜索步骤dx
dx=0.0001 // or dx=function(|f(x0),f(x0+0.0001)|)
if (|f(x0-dx)-y|<|f(x0+dx)-y|) dx=-dx;
所以找到哪种方式更接近解决方案。应该以某种有意义的方式选择0.0001
常量。太小会减慢过程太大会错过颠簸。对于动态步骤,您可以使用第一个推导的大小或解决方案本身的距离,例如dx=sign(dx)*abs(f(x)-y)
以及dx==0
是否停止......
搜索最接近的匹配
while (|f(x0)-y|>|f(x0+dx)-y|) x0+=dx;
停在最近的比赛上。如果您想要动态步骤,那么还要添加dx=function(|f(x0),f(x0+0.0001)|)
内部循环
现在您绑定了搜索<x0-dx,x0+dx>
所以你可以按照上面的链接使用二进制近似搜索。
如果找不到足够的解决方案
然后你得到一些错过的颠簸或太大的步骤或初始猜测点是具有对称函数形状的极值点导致初始方向估计失败。因此,您可以更改初始x0
常量。
答案 1 :(得分:1)
我刚刚发布了一个精确地执行此操作的python包,并且必须经历许多这些警告。你可能想借用它的一些想法: https://pypi.python.org/pypi/pynverse
它基本上遵循这一策略:
Brent
方法找到bounded_f(x)-y0的根,确保最小化的算法从原始内部的某个点开始通过将ref1,ref2设置为括号来设置间隔。只要超出允许的间隔,bounded_f就会返回无限,迫使算法返回到间隔内搜索。答案 2 :(得分:0)
我建议先做小范围,而不是以指数方式扩展。如果使用[-1,1],[-2,2],[-4,4]等范围,即使在最坏的情况下,开销也会保持不变。