有没有比O(N*W)算法更好的方法来计算窗口中固定X位置的滑动窗口最大斜率?

huangapple go评论69阅读模式
英文:

Is there a better than O(N*W) algorithm for calculating the sliding window maximum slope to a point at fixed X position in the window?

问题

给定两个序列 H[t]F[t] 和一个窗口大小 W;目标是找到第三个序列 M[t],使得 M[t] 是从点 (t-1, H[t-1]) 到点 (t..t+W, F[t+W]) 所有斜率中的最大值。

图形示例(请注意,仅显示 H[t] 的Y截距 H[t=0]):
图例
M[t=0] 的值是蓝线的斜率。

这样做的目的是生成一种类似于 '松散' 的信号包络。在这个应用中,H[t-1] 实际上依赖于前一个窗口中 M[t-1] 的值,但具体情况与此算法无关。更重要的是:这是一个在线过程,窗口之外的数据不可访问,并且需要立即为每个窗口提供答案。

粗暴的方法是 O(N*K),即对于每个窗口的每个样本 (F[t..t+W]) 计算斜率,但对于这个应用可能不合适(窗口大小在2k-20k样本的范围内,需要实时性能)。

起初,我以为可以几乎与 滚动最大值问题 几乎相同的方式解决,使用一个双端队列。我最终发现,变化的 H[t] 不会保留斜率的总顺序(考虑任意两个样本,如果 H[t] 相对于两个样本形成的直线发生变化,它们的最大斜率关系会颠倒),因此双端队列会被破坏。

另一个这种方法的问题是,虽然该算法整体上是 O(N)(每个窗口平均 O(1)),但对于需要清除完整双端队列的某些窗口,可能会出现 O(W) 的“抖动”(公平地说,这可能具有足够小的常数,可以接受)。

我正在尝试的下一种方法是保持样本值的二叉搜索树(可以每个窗口更新为 O(log(W))),并且 以某种方式 使用它(以及其他数据结构或数学属性)来丢弃大部分斜率计算,但似乎是死胡同(快速的 X 和 Y 搜索并不意味着快速的 Y/X 查找)。

另外,这个问题是否有一个更简洁的名称?希望我能够清楚地表达了问题的要点。

英文:

Given two series H[t], F[t], and a window size W; the objective is to find a third series M[t], such that M[t] is the maximum of all slopes from point (t-1, H[t-1]) to points (t..t+W, F[t+W]).

Graphical example (note that H[t] is not shown, only its Y intercept H[t=0]):
Plot.
The value of M[t=0] is the slope of the blue line.

The purpose of this is to generate a sort of 'loose' signal envelope. In this application, H[t-1] is in fact dependent on the value of M[t-1] in the previous window, but the specifics are external to this algorithm. More importantly: it is an on-line process, data beyond the window is not accessible, and it requires giving the answer immediately for each window.

The brute force approach O(N*K), that is, evaluating the slope for every sample (F[t..t+W]) for every window, might not be appropriate for this application (window size is in the realm of 2k-20k samples, real-time requirements)

At first I thought it could be solved almost identically to the rolling maximum problem, with a deque. I eventually found that varying H[t] does not preserve the total order of the slopes (consider any two samples, if H[t] changes 'sides' relative to the line formed by the two samples, their maximum slope relation is reversed), and thus the deque becomes corrupted.

Yet another problem with that kind of approach is that, while that algorithm is in a whole O(N) (O(1) per window on average), it can have O(W) 'jitter' for certain windows that have to 'purge' a full deque (in fairness, that probably has a small enough constant to be acceptable).

The next approach I'm trying is to keep a BST of the sample's values (which can be kept updated for O(log(W)) per window) and somehow use it (along some other data structure or mathematical property) to discard most of the slope calculations, but it seems to be a dead end (Fast X and Y search does not imply fast Y/X lookup).

As an aside, does this problem has a less verbose name? I hope I managed to get the point across.

答案1

得分: 0

让我们首先考虑一个基于块的算法。

给定 H[0...W-1]F[1...2W],我们可以在 O(W log W) 时间内计算 M[0...W-1]

这将让你在 O(N * log W) 时间内解决整个问题,但在流式音频上下文中,这意味着引入了大约2W个样本的延迟。如果这对你有用,那太好了!如果不行,我们可以讨论一种巧妙的方法来减少延迟。

基于块的算法的关键在于,从任何H点到其目标F窗口的最大斜率 总是 在F窗口的上凸壳上。如果你有一个F窗口的凸壳,你可以通过二分搜索找到任何H点的目标,因为凸壳的斜率是单调递减的。如果猜测的F点太早,那么凸壳的后续部分将指向H点的 下方。如果猜测的F点足够晚,那么它要么是最后一个点,要么后续部分将指向H点的 上方或等于

因此,首先使用单调链算法,向前扫描,计算从 F[W]F[2W] 的所有F点的上凸壳。在这个过程中,你将得到该窗口所有前缀的上凸壳。每个前缀都是恰好一个H点的目标窗口的尾部。将H值设置为其尾部窗口中的最大斜率。

然后再次使用单调链算法,这次向后扫描,计算从 F[W-1]F[1] 的所有F点的上凸壳。在这个过程中,你将得到该窗口所有后缀的上凸壳。每个后缀都是前一个H点的目标窗口的剩余部分。计算从H点的最大斜率,并保存下来,如果它比你已经有的斜率更大。

完成后,你就得到了每个H点的最终斜率。

英文:

Let's consider a block-based algorithm first.

Give H[0...W-1] and F[1...2W], we can calculate M[0...W-1] in O(W log W) time.

This will let you solve your whole problem in O(N * log W) time, but in a streaming audio context, that means introducing a 2W-sample delay or so. If that will do the job for you, then great! If not, we can discuss a tricky way to reduce that after.

The key to the block-based algorithm is that the maximum slope from any H-point into its target F-window is always on the upper convex hull of the F-window. If you have the convex hull for an F-window, you can find the target for any H-point by binary search, because the slope of the convex hull is monotonically decreasing. If a guessed F-point is too early, then the following segment of the convex hull will point back underneath the H-point. If the guessed F-point is late enough, then it's either the last point, or the following segment will point back at or over the H-point.

So to start use the monotone chain algorithm, scanning forward, to compute the upper convex hull of the F-points from F[W] to F[2W]. In the process you will get the upper convex hulls of all the prefixes of that window. Each prefix is the tail-end of the target window for exactly one H-point. Set the H-value to the maximum slope to a point in it's tail-end window.

Then use the monotone chain algorithm again, this time scanning backward, to compute the upper convex hull of all the F-points from F[W-1] to F[1]. During this process you'll get the upper convex hulls of all the suffixes of that window. Each suffix is the remaining part of the target window for the immediately preceding H-point. Calculate the maximum slope from the H-point, and save it if it's bigger than the one you already have.

When you're done, you have the final slopes for each H-point.

huangapple
  • 本文由 发表于 2023年7月11日 08:40:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/76658077.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定