求帕累托边界的具体分治算法的参考实现

问题描述

给定任何部分可排序元素的集合,可以将所述集合的最大值视为不小于集合中任何其他元素的所有元素。当这个集合是一组 n 维向量时会发生一种特殊情况(在 Rust 中,我们可以将 (D1,D2,D3,...,Dn) 之类的东西作为 n 维向量的类型,而 Vec<(D1,Dn)> 将是一种集合类型n 维向量),其中每个维度 Di 是完全有序的,偏序定义为 (a1,a2,a3,an)<=(b1,b2,b3,bn) iff (a1<=b1) && (a2<=b2) && (a3<=b3) && ... && (an<=bn)。这种情况下的最大值在多个域中都是众所周知的,因为如果将维度解释为要优化的目标,它就是帕累托边界,如果将维度解释为表的列,则它是天际线查询的结果。

Bentley80 和其他几篇论文中,描述了一种找到此最大值的有效算法。这是我目前对其外观的理解(所以请阅读原始描述,因为这个描述来自一个实际上并不知道它是如何工作的人!):


参数:向量集合 V:Vec<(D1,Dn)> where D1,Dn:Ord,按其第一个维度 D1 排序,以及数量 n>=3 的维度。

结果:集合 M 恰好具有 V 的最大值。

步骤:

  1. 如果集合只包含一个向量或为空,我们就完成了; M=V。否则,请继续执行第 2 步。
  2. V 上选取 Dn 的中值,将集合分成两半,所有向量的 Dn 分量小于 V1 中的中值,其他向量在V2
  3. 递归计算V1V2的最大值,分别得到M1M2
  4. 如果 n == 3,则沿 M_1.append(M_2) 迭代 D1,从具有最大 D1 分量的向量开始,以最小的向量结束。对于本次迭代中的每个向量 v,如果 vM2 中,则将其放入 M,如果它是迄今为止见过的最大的,则记录其 D2 分量.否则,vM1 中;如果其 M 分量不小于观察到的 D2 向量记录,则将其放入 M1。迭代完成后,我们也完成了;结果是M
  5. 如果n > 3,递归计算M1.append(M2)的最大值,但以n - 1为考虑的最大维度,并跟踪哪些向量在M1中,哪些向量在M2

不幸的是,我无法自己实现它。所以我问 StackOverflow:有人能提供一个简单、易懂的算法实现吗?不需要特定的编程语言,实际上在这种情况下伪代码可能是最明确的选择,但我必须要求细节不遗漏。在我看来,像 C 或 Rust 这样的系统语言会对此有所帮助。

当然,我自己也尝试过(在 Rust 中),但有一些事情让我感到困惑:

  • a.您如何有效地将 Dn 中的集合分成两半? Rust 在其标准库中有一种求中值的方法,但它是不稳定的(在排序意义上),我们不能直接使用它,因为我们需要保留 D1 排序。无论如何,人们可能会浪费一堆空间/分配来做这件事(克隆集合,在克隆上调用标准库方法并找到中位数,然后迭代原始向量,推送其 Dn 分量小于将中位数转化为 V1 并将较大的转化为 V2),但我想知道是否有更好的方法
  • b.重复元素很棘手。在两个地方,特别是:在第 2 步中,如果中位数有很多重复,人们会想知道是否需要特别注意将它们放在哪里(非中位数元素的数量重要吗?),甚至可以退化为所有元素都等于中位数的情况,这意味着当发生这种情况时,需要一个特殊的步骤来简单地跳过该维度。并且在第 4 步中,可以同时在 D1M1 中存在许多具有相同 M2 分量的向量。我认为在这种情况下需要做的是,算法必须迭代具有该 D1 组件的所有元素,跟踪 M2 达到的最高记录向量,然后才决定是否有 M1 向量进行切割。
  • c.您可能已经注意到,第 5 步提到跟踪哪些向量来自 M1,哪些向量来自 M2,但没有其他步骤使用此信息。原来我也不知道是怎么回事。我的意思是,我读过这篇论文,我“明白了”;因为 M2 向量的 Dn 分量比任何 M1 向量都大,这意味着,在递归调用中,我们只考虑 n - 1 维,我们还必须跟踪向量来自何处,以便每当 v2 <= v1v1 被视为 v2 维向量时,n - 1 来自v2M2 来自v1,我们知道要说M1v1 实际上是不可比的。但是我们不直接在算法中比较向量!实际比较(向量的 v2 分量之间)在步骤 4 中完成,此时我们与其他维度相距甚远,我不知道如何将来自它们的信息整合到步骤中。我最好的猜测是用额外的位向量“增强”每个向量,每个维度一位,以便在每次降维递归之前,通过 D2M1 中的每个向量,翻转适当的位,然后呢?在第 4 步的迭代部分,我认为您必须跟踪整个 M2 记录向量?在这一点上,我基本上停止了自己的尝试。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)