多元二分法

时间:2010-08-18 15:18:21

标签: language-agnostic math linear-algebra numerical-methods bisection

我需要一种算法来执行2D二分法来解决2x2非线性问题。示例:我想要同时解决的两个方程f(x,y)=0g(x,y)=0。我非常熟悉一维二分法(以及其他数值方法)。假设我已经知道解决方案位于边界x1 < x < x2y1 < y < y2之间。

在网格中,起始边界为:

    ^
    |   C       D
y2 -+  o-------o
    |  |       |
    |  |       |
    |  |       |
y1 -+  o-------o
    |   A       B
    o--+------+---->
       x1     x2

我知道值f(A), f(B), f(C) and f(D)以及g(A), g(B), g(C) and g(D)。为了开始二分,我想我们需要将这些点沿着边缘和中间分开。

    ^
    |   C   F   D
y2 -+  o---o---o
    |  |       |
    |G o   o M o H
    |  |       |
y1 -+  o---o---o
    |   A   E   B
    o--+------+---->
       x1     x2

现在考虑组合的可能性,例如检查f(G)*f(M)<0 AND g(G)*g(M)<0是否看起来势不可挡。也许我觉得这有点过于复杂,但我认为应该有一个多维版本的Bisection,就像Newton-Raphson可以很容易地使用梯度算子进行多维处理。

欢迎提供任何线索,评论或链接。

7 个答案:

答案 0 :(得分:4)

抱歉,虽然二分法在1-d中起作用,但在较高维度上失败。您只能使用有关区域角落处的函数和内部点的信息,将2区域划分为子区域。用Mick Jagger的话来说,"You can't always get what you want"

答案 1 :(得分:4)

我刚从geometrictools.comC++ code偶然发现了答案。

编辑:代码现在位于github

Title

答案 2 :(得分:3)

我只会沿着一个尺寸分割区域,交替尺寸。单个函数存在零的条件是“你在区域的边界上有两个不同的符号点”,所以我只是检查这两个函数。但是,我不认为它会运行良好,因为特定区域中的两个函数的零保证共同的零(这甚至可能存在于不符合标准)。

例如,请看这张图片:

alt text

除了ABEDEFIH在其边界上的行为外,您无法区分正方形f()g()。但是,ABED不包含公共零,EFIH不包含。

这类似于使用例如的区域查询。 kD-tree,如果你可以肯定地确定一个区域不包含例如零。 f。不过,在某些情况下,这可能会很慢。

答案 3 :(得分:1)

如果你可以假设(根据你对木片的评论)f(x,y)= 0定义连续单调函数y = f2(x),即对于每个x1 <= x&lt; = x2 y有一个唯一的解决方案(由于f的混乱形式你不能解析地表达它),同样y = g2(x)是一个连续的单调函数,那么就有办法找到关节溶液

如果你可以计算f2和g2,那么你可以在[x1,x2]上使用1-d二分法来求解f2(x)-g2(x)= 0。并且你可以通过在[y1,y2]上再次使用1-d二分来解决f(x,y)= 0,对于你需要考虑的任何给定的固定x(x1,x2,(x1 + x2) / 2,等等 - 这是连续单调性有用的地方 - 同样对于g。您必须确保在每个步骤后更新x1-x2和y1-y2。

这种方法效率可能不高,但应该有效。当然,许多双变量函数不与z平面相交为连续单调函数。

答案 4 :(得分:1)

这与在矢量字段中查找关键点类似(见http://alglobus.net/NASAwork/topology/Papers/alsVugraphs93.ps)。

如果在四边形的顶点有f(x,y)和g(x,y)的值,那么你就是一个离散问题(这样你就没有f(x)的解析表达式,y)和g(x,y)也不是四边形内其他位置的值,那么你可以使用双线性插值来得到两个方程(对于f和g)。对于2D情况,解析解将是二次方程,根据解(1根,2个实根,2个虚根),您可以在四边形内部或外部有1个解,2个解,无解,解。< / p>

如果您具有f(x,y)和g(x,y)的分析函数并想要使用它们,则这没有用。相反,你可以递归地划分你的四边形,但正如jpalecek2nd post)已经指出的那样,你需要一种方法来通过确定一个可以确保你没有的测试来阻止你的分裂。四边形内的零。

答案 5 :(得分:1)

让f_1(x,y),f_2(x,y)是两个相对于x和y连续且单调的函数。问题是要解决系统f_1(x,y)= 0,f_2(x,y)= 0。

交流方向算法如下所示。在此,这些行描述了集合{f_1 = 0}和{f_2 = 0}。显而易见,算法的移动方向(从右向下或从左向上)取决于求解方程的顺序f_i(x,y)= 0(例如,求解f_1(x,y)= 0 wrt x然后求解f_2(x,y)= 0 wrt y或先求解f_1(x,y)= 0 wrt y,然后求解f_2(x,y)= 0 wrt x)。

鉴于最初的猜测,我们不知道根在哪里。因此,为了找到系统的所有根,我们必须朝两个方向移动。

答案 6 :(得分:1)

我在优化方面没有太多经验,但我使用问题描述的二分算法构建了解决此问题的方法。我认为有必要修复我的解决方案中的错误,因为在某些情况下它会计算根的两倍,但我认为这很简单,稍后会尝试。

编辑:我似乎是 jpalecek 的评论,现在我认为我假设的某些前提是错误的,但这些方法仍然适用于大多数情况。更具体地说,只有当两个函数在相反方向上改变信号时才保证零,但需要处理顶点为零的情况。我认为可以为此构建一个合理且令人满意的启发式算法,但它有点复杂,现在我认为更有希望获得 f_abs = abs(f, g) 给出的函数并构建一个启发式算法来查找局部最小值,寻找梯度边中点的方向。

简介

考虑问题中的配置:

    ^
    |   C       D
y2 -+  o-------o
    |  |       |
    |  |       |
    |  |       |
y1 -+  o-------o
    |   A       B
    o--+------+---->
       x1     x2

有很多方法可以做到这一点,但我选择只使用角点(A、B、C、D)而不是像问题所暗示的那样使用中间或中心点。假设我有你描述的两个函数 f(x,y) 和 g(x,y) 。事实上,它通常是一个函数 (x,y) -> (f(x,y), g(x,y)).

步骤如下,最后有简历(附Python代码)。

分步说明

  1. 在相邻点计算每个标量函数(f 和 g)的乘积。计算每个变化方向(轴、x 和 y)的最小乘积。
Fx = min(f(C)*f(B), f(D)*f(A))
Fy = min(f(A)*f(B), f(D)*f(C))

Gx = min(g(C)*g(B), g(D)*g(A))
Gy = min(g(A)*g(B), g(D)*g(C))

它通过矩形的两条对边观察乘积并计算它们中的最小值,如果为负,则表示存在信号变化。这有点多余,但工作得很好。或者,您可以尝试其他配置,例如使用点(问题中显示的 E、F、G 和 H),但我认为使用角点是有意义的,因为它更好地考虑了矩形的整个区域,但它只是一个印象。

  1. 计算每个函数的最小牵引轴。
F = min(Fx, Fy)
G = min(Gx, Gy)

这个值表示矩形内每个函数 f 和 g 都存在零。

  1. 计算它们的最大值:
max(F, G)

如果 max(F, G) < 0,则矩形内有根。另外,如果 f(C) = 0 和 g(C) = 0,也有一个根,我们也这样做,但如果根在另一个角落,我们忽略他,因为其他矩形会计算它(我想避免重复计算根)。以下声明继续:

guaranteed_contain_zeros = max(F, G) < 0 or (f(C) == 0 and g(C) == 0)

在这种情况下,我们必须递归地打破区域,直到矩形达到我们想要的大小。

否则,矩形内可能仍然存在根。正因为如此,我们必须使用一些标准来打破这个区域,直到我们有一个最小的粒度。我使用的标准是断言当前矩形的最大尺寸小于原始矩形的最小尺寸(以下代码示例中的 delta)。

简历

这段 Python 代码简历:

def balance_points(x_min, x_max, y_min, y_max, delta, eps=2e-32):

    width = x_max - x_min
    height = y_max - y_min
    x_middle = (x_min + x_max)/2
    y_middle = (y_min + y_max)/2

    Fx = min(f(C)*f(B), f(D)*f(A))
    Fy = min(f(A)*f(B), f(D)*f(C))
    Gx = min(g(C)*g(B), g(D)*g(A))
    Gy = min(g(A)*g(B), g(D)*g(C))

    F = min(Fx, Fy)
    G = min(Gx, Gy)

    largest_dim = max(width, height)
    guaranteed_contain_zeros = max(F, G) < 0 or (f(C) == 0 and g(C) == 0)

    if guaranteed_contain_zeros and largest_dim <= eps:
        return [(x_middle, y_middle)]
    elif guaranteed_contain_zeros or largest_dim > delta:
        if width >= height:
            return balance_points(x_min, x_middle, y_min, y_max, delta) + balance_points(x_middle, x_max, y_min, y_max, delta)
        else:
            return balance_points(x_min, x_max, y_min, y_middle, delta) + balance_points(x_min, x_max, y_middle, y_max, delta)
    else:
        return []

结果

我在个人项目(GitHub here)中使用了类似的代码,它绘制了算法和根的矩形(系统在原点有一个平衡点): Rectangles

效果很好。

改进

在某些情况下,该算法计算相同零的两倍。我认为这可能有两个原因:

  • 在这种情况下,函数在相邻矩形处给出的结果几乎为零(因为数字截断)。在这种情况下,补救措施是增加 eps(增加矩形)。我选择了 eps=2e-32,因为 32 位是精度的一半(在 64 位架构上),那么该函数可能不会给出零......但这更像是一个猜测,我不现在如果更好。但是,如果我们减少很多 eps,它会推断出 Python 解释器的递归限制。
  • f(A)、f(B) 等接近于零且乘积被截断为零的情况。我认为如果我们使用 f 和 g 信号的乘积代替函数的乘积,它可以减少。
  • 我认为可以改进丢弃矩形的标准。可以考虑函数在矩形区域中的变化程度以及函数为零的距离。也许是角落函数值的平均值和方差之间的简单关系。另一种方式(更复杂),我们可以使用堆栈来存储每个递归实例上的值,并保证这些值收敛以停止递归。