9

我需要一种算法来执行二维二等分法来解决 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似乎势不可挡。也许我让这有点太复杂了,但我认为应该有一个多维版本的二分法,就像牛顿拉夫森可以很容易地使用梯度算子进行多面化一样。

欢迎任何线索、评论或链接。

4

7 回答 7

7

抱歉,虽然二分法在一维中有效,但在更高维度上却失败了。您根本无法仅使用有关区域拐角处的函数和内部点的信息将二维区域分解为子区域。用 Mick Jagger 的话来说,“你不能总是得到你想要的”

于 2010-08-18T16:23:39.990 回答
6

我刚刚从geometrictools.comC++ 代码中偶然发现了这个问题的答案。

编辑:代码现在在github 上

标题

于 2014-01-08T22:17:02.713 回答
5

我只会沿单个维度分割区域,交替维度。您存在单个函数为零的条件是“您在区域边界上有两个不同符号的点”,所以我只需检查这两个函数。但是,我认为它不会很好地工作,因为特定区域中两个函数的零点不能保证共同的零点(这甚至可能存在于不符合标准的不同区域中)。

例如,看看这张图片:

替代文字

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

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

于 2010-08-18T16:04:53.210 回答
2

如果您可以假设(根据您对木片的评论)f(x,y)=0 定义了一个连续的单调函数 y=f2(x),即对于每个 x1<=x<=x2,y 都有一个唯一的解(由于 f) 的形式混乱,您无法解析地表达它,同样 y=g2(x) 是一个连续的单调函数,那么有一种方法可以找到联合解。

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

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

于 2010-08-18T22:58:41.927 回答
2

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

编辑:我似乎是 的评论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 )中使用了类似的代码,它绘制了算法的矩形和根(系统在原点有一个平衡点): 矩形

它运作良好。

改进

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

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

相反,如果您有 f(x,y) 和 g(x,y) 的分析函数并想使用它们,那么这没有用。相反,您可以递归地划分您的四边形,但是正如jpalecek第 2 篇文章)已经指出的那样,您需要一种方法来通过找出一个可以确保您在四边形内没有零的测试来停止您的划分。

于 2011-12-15T19:51:40.567 回答
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)。

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

于 2019-10-22T21:20:14.513 回答