(自适应?)函数绘图的算法

计算科学 算法 可视化
2021-12-16 21:08:28

我正在寻找算法来为可能有也可能没有奇点的函数绘制标准二维图。目的是写一个“Mini-CAS”,所以对函数的类型没有先验知识,用户要图。

这个问题很老了,所以我想文献中一定有一些标准的算法。这一次,我通过谷歌找到参考资料的成功率并不高。

我确实找到了一种有趣的算法,即来自 “YACAS - Book of algorithm”的名为“Adaptive function plotting”的算法。

简而言之:

  • 有标准算法吗?
  • 是否有用于已知难以绘制函数的测试套件?
  • 有哪些有趣的论文值得阅读?
4个回答

了解其他 CAS 如何做到这一点可能会对您有所帮助。

据我所知,Mathematica 使用以下基本算法的变体来绘制单变量函数f(x)或参数曲线(x(t),y(t))(我假设f(x)对于这个描述)。

  1. 从绘图域上规则间隔的点网格开始。(在 Mathematica 中有一个参数来控制取多少,叫做PlotPoints。)

  2. 查看每一对连续的线段(由三个连续的点定义,(x1,f(x1)),(x2,f(x2)),(x3,f(x3))) 并在两个段的中间插入一个新的采样点 (x1+x22x2+x32) 如果它们的角度大于阈值。

  3. 如果我们还没有达到迭代限制(MaxRecursion在 Mathematica 中设置),从第 2 步开始重复。

其中一些在 Stan Wagon 的 Mathematica in Action 一书中进行了讨论,您可以在 Google Books 上看到

我之前实现了这个算法,以便更好地控制我的昂贵计算函数被评估了多少次。这是第 2 步的 Mathematica 代码:

nd[{points_, values_}] :=
Transpose@{(Drop[points, 1] + Drop[points, -1])/2,
Differences[values]/Differences[points]}

subdivide1d[result_, resolution_, maxAngle_: 10] :=
  Module[
    {deriv, angle, dangle, pos, nf},
    deriv = nd[result\[Transpose]];
    angle = ArcTan[#2] & @@@ deriv;
    dangle = Differences[angle];
    pos = Flatten@Position[dangle, d_ /; Abs[d] > maxAngle/180 Pi];
    pos = Union[pos, pos + 1];
    nf = Nearest[result[[All, 1]]];
    Select[deriv[[pos, 1]], Abs[# - First@nf[#]] > resolution &]
  ]

我已经在 GitHub 上实现了Mathematica 的自适应采样例程(它是一个 C 文件,上到头文件的源代码树)。很久以前,我在一本关于 Mathematica 的大书中找到了对该例程的描述,并且我已经使用这个实现的变体已经有一段时间了。它基本上在感兴趣的域上进行粗略的线性采样,然后返回以细化高曲率区域。可能会遗漏一些非常清晰的特征,但在实践中我发现这种情况非常罕见。该文件还包含并行版本。

函数图上的 MathWorld 网页包含对几篇似乎与自适应函数绘图相关的论文的引用。引用页面:

绘制图形的良好例程使用自适应算法,在函数变化最快的区域绘制更多点(Wagon 1991,Math Works 1992,Heck 1993,Wickham-Jones 1994)。Tupper (1996) 开发了一种算法 [...]

另一方面,在谷歌上我偶然发现了一篇论文

www.cs.uic.edu/~wilkinson/Publications/plotfunc.pdf

这解释了如何正确选择域和其他内容。我希望它们对你有用。

我找到了这个主题,并认为我应该分享开发者问题页面,以便将其添加到 Julia 库 Plots.jl。从 Mathematica 实现的注释开始,我们尝试了一系列技术来看看什么会产生好的结果。添加一些修剪、不完全从间隔端点开始的小扰动、递归限制和双网格误差估计器都是“让它恰到好处”所必需的。该线程还为您指出了实现的开源代码。所以它确实需要一些调整,但是添加这些功能使它非常健壮(根据测试,如线程中所示)。