有什么简单的方法可以自适应地采样2D函数?


22

我有一个二维函数,我想对它的值进行采样。该函数的计算非常昂贵,而且形状复杂,因此我需要找到一种方法,以最少的采样点获取有关其形状的最多信息。f(x,y)

有什么好的方法可以做到这一点?

到目前为止我有什么

  • 我从已经计算了函数值的现有点集开始(这可以是点的方格或其他形式)。

  • 然后,我计算这些点的Delaunay三角剖分。

  • 如果在Delaunay三角两个相邻点足够远()和函数值不同充分地它们(> Δ ˚F),然后我插入一个新的中点其间它们。我为每个相邻的点对执行此操作。>ΔX>Δf

这种方法有什么问题?

好吧,它工作得相对较好,但是在与此功能类似的功能上并不理想,因为采样点往往会“越过”山脊,甚至不会注意到那里。

Mathematica图形

它会产生如下结果(如果初始点网格的分辨率足够粗糙):

Mathematica图形

上图显示了计算函数值的点(实际上是它们周围的Voronoi单元)。

Mathematica图形

上图显示了从相同点生成的线性插值,并将其与Mathematica的内置采样方法(大约相同的起始分辨率)进行了比较。

如何改善呢?

我认为这里的主要问题是我的方法基于渐变来决定是否添加细化点。

添加细化点时最好考虑曲率或至少考虑二阶导数。

当我的点的位置完全不受约束时,考虑二阶导数或曲率的一种非常简单的实现方法是什么?(我不一定要有一个正方形的起点,理想情况下应该是通用的。)

还是有其他简单的方法可以以最佳方式计算精炼点的位置?

我将在Mathematica中实现这一点,但是这个问题主要与方法有关。对于“易于实现”这一点,确实可以认为我正在使用Mathematica(即到目前为止,这很容易完成,因为它具有用于执行Delaunay三角剖分的程序包)

我将其应用于什么实际问题

我正在计算一个相图。它具有复杂的形状。在一个区域中,其值为0,在另一个区域中,其值为0到1。两个区域之间有一个急剧的跳跃(不连续)。在函数大于零的区域中,既有一些平滑变化,也有一些不连续。

该函数值是根据蒙特卡洛模拟计算得出的,因此偶尔会出现不正确的函数值或噪声(这种情况很少见,但是对于很多点,它会发生,例如,当未达到稳态时,一些随机因素)

已经在Mathematica.SE上问过这个问题,但由于它仍处于私测阶段,所以无法链接到它。这里的问题是关于方法,而不是实现。


回复@suki

您是否建议这种划分类型,即在三角形的中间放置一个新点?

Mathematica图形 Mathematica图形 Mathematica图形 Mathematica图形

我在这里担心的是,似乎需要对该区域的边缘进行特殊处理,否则它将产生非常长且非常细的三角形,如上所示。你纠正了吗?

更新

我描述的方法和@suki提出的基于三角形进行细分并将细分点置于三角形内的建议都出现了一个问题,即当存在不连续性时(如我的问题),在执行步骤之后可能会重新计算Delaunay三角剖分导致三角形发生变化,并且可能会出现一些大三角形,在三个顶点中它们具有不同的函数值。

这是两个示例:

例1 例2

第一个显示围绕直线不连续采样时的最终结果。第二个显示了类似情况下的采样点分布。

有什么简单的方法可以避免这种情况?目前,我只是在细分那些在重新三角化之后消失的egdes,但这感觉就像是破解,需要谨慎进行,因为在对称网格(例如方形网格)的情况下,存在多个有效的Delaunay三角剖分,因此边缘可能会改变重新三角化后随机。


在这个问题上有什么新进展吗?
Andrei 2014年

Answers:


10

我曾经研究过类似的问题。

我认为我们的实现之间的主要区别在于,我是根据三角形而不是边缘来选择在何处添加点。我还选择了三角形内而不是边缘上的新点。

我的感觉是,在三角形内添加点将使旧点到新点的平均距离略有增加,从而使其效率更高。

无论如何,使用三角形而不是边缘的另一个好处是,它给出了梯度矢量的估计值,而不是沿该特定边缘的斜率。

在我的matlab代码中,我使用了一个基类来处理大多数机器,并提供了一些抽象方法:

  • weight(self) 确定下一个要细分的三角形的优先级。
  • choosePoints(self,npoints = "auto") 根据每个三角形的权重决定要评估的新点。

我发现此设置非常灵活:

  • 将子类的weight()函数设置为三角形的面积会产生恒定的网格密度。
  • 设置weight()以计算平均函数值乘以三角形的面积得出的一种准随机概率采样。
  • var(triangle.zs)对于具有二进制输出的函数,使用可以做到,我的感觉是将二等分搜索推广到一个以上的维度。
  • 使用可以area + var(triangle.zs)非常有效地在各处保持恒定的密度,并在任何坡度(几乎与现在一样)上增加密度。

我使用z值的方差来估算一阶效果(斜率)的重要性,因为方差永远不会像斜率那样达到无穷大。

对于最后一个示例,背景密度很好,因为我在低值空间中搜索高值的不连续斑点。因此它会慢慢填充整个网格,当它找到一个斑点时,由于我对渐变施加了很高的权重(并且它只填充了顶部的n三角形),因此它会一直专注于整个斑点的边缘每次迭代)。最后,我知道没有(大小合理的)斑点(或斑点中的孔)大于所产生的背景网格密度。

像您一样,我的结果中确实有一些不好的地方,对我来说也不是问题,因为错误如此,如果您重新运行附近的点,它们可能会给出正确的答案。我只会在坏点周围出现网格密度增加的现象。

无论您做什么,我总是建议使权重与三角形的大小有关,以便在所有其他条件相同的情况下,首先分解大三角形。

也许对您来说,解决方案是使我的方法更进一步,而不是基于该三角形单元格的内容来评估三角形,而要基于那个和所有三个相邻三角形进行评估。

那将包含足够的信息来获得完整的黑森州矩阵的估计。您可以通过z = c1*x + C2*y c11*x^2+c12*x*y+c22*y^2对感兴趣的三角形中的所有顶点进行最小二乘拟合来获得它(首先将坐标系居中于三角形上)。

我不会直接使用渐变或Hessian(这些常数),因为它们会在不连续处达到无穷大。

相对于这些点的平面近似值,z值的平方和误差也许是衡量二阶效应有趣程度的有用方法。


更新:

在我看来,这很合理。

我从来没有真正绕过特殊的边缘。这让我有些困扰,但是对于我正在做的事情,仅从边缘周围的许多点开始就足够了。

更优雅的是将我们的两种方法(对边缘和三角形加权)结合起来。然后,如果边缘太长,将其切成两半...我喜欢将概念推广到更高尺寸的方式(但是数字会很快变大)...

但是,由于您不希望网格的主体具有高长宽比的三角形,因此可以使用Matlab的自由边界函数之类的函数来查找边界,然后在边界上以较小的维度运行相同的算法。如果做得正确,例如在一个立方体上,您可以在立方体的边缘,表面和内部获得相同的网格密度。有趣。

我从来没有找到一个好的解决方案的一件事是,我的版本永远不会探索初始点集的凸包之外。


我也考虑过先使用三角形,但首先遇到一些技术问题(此后便解决了),后来我认为无论如何都不会更好。问题:您将新观点放在哪里?在三角形的中间?我之所以没有这样做,是因为我希望它会创建一些非常长且细的三角形。我会尽快以我了解您的信息来更新我的帖子,以便您可以验证我是否正确:-)谢谢!
Szabolcs 2012年

能否请您查看我的修改和说明?
Szabolcs 2012年

事实证明,无论我使用哪种细分方案,都无法避免使用特殊的套管边缘。在我的情况下,垂直于边缘但与边缘不平行存在高梯度,如果不特殊设置边缘,这会使效率低下。
Szabolcs

我发现的另一个问题是重新三角剖分会导致三角形偶尔出现在顶点具有不同函数值的地方。我最终得到了这样的结果:i.stack.imgur.com/nRPwi.png是线性插值的密度图,而i.stack.imgur.com/208bP.png是采样点(不完全相同)。这只是沿直边的不连续。你遇到这个问题了吗?如果是,您如何解决?在每个细分步骤之后,您是否完全重新进行了重新三角化?
Szabolcs

我不确定三角剖分在这里真的意味着什么。您评估的每个点都是该点的函数值,那么为什么不在无网格方法中使用类似的东西呢?en.wikipedia.org/wiki/Smoothed-particle_hydrodynamics您也可以通过这种方式估算导数……
meawoppl 2012年

0

我认为您的启发式方法的主要问题在于,您仅考虑一维梯度,因此,在dfdx小但dfdy大的区域(如示例中所示),在寻找时会丢失点在“错误的”维度中。

一种快速的解决方法是考虑四个点的集合,并取其重心并近似| dfdx | + | dfdy |。用这四个点。另一种选择是获取三个点(即三角形),并在其上获取曲面的最大坡度。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.