在列表中查找匹配对的算法
我将在下面以我想要的精确形式表述该问题:
给出: 两个浮点列表 N
和 D
,长度 k
相同(k
是 2 的倍数)。 已知对于所有i=0,...,k-1
,存在j != i
使得D[j]*D[ i] == N[i]*N[j]
。 (我使用从零开始的索引)
返回: 一个(长度k/2
)对(i,j)
的列表,使得D[j]*D[i] == N[i]* N[j]
。 返回的对可能不是唯一的(任何有效的对列表都可以)
该算法的应用是查找广义回文特征值问题的特征值的倒数对。 等式条件等价于 N[i]/D[i] == D[j]/N[j],但在分母为零时也有效(这是一种确定的可能性)。特征值问题中的简并性导致这些对不唯一。
更一般地说,该算法相当于:
给定: 长度为 k
的列表 X
(k
是 2 的倍数)。 已知对于所有 i=0,...,k-1
,存在 j != i
使得 IsMatch(X[i], X[j])
返回 true,其中 IsMatch
是一个布尔匹配函数,保证对所有 j != i
至少一个返回 true代码>我。
返回: 一个(长度k/2
)对(i,j)
的列表,使得所有对的IsMatch(i,j) == true
在列表中。 返回的对可能不是唯一的(任何有效的对列表都可以)
显然,我的第一个问题可以根据第二个问题来表述 IsMatch(u,v) := { (u - 1/v) = = 0 }。现在,由于浮点精度的限制,永远不会有完全相等的情况,所以我想要最小化匹配误差的解决方案。换句话说,假设 IsMatch(u,v)
返回值 u - 1/v
并且我希望算法返回一个列表,IsMatch 返回该列表的最小集的错误。这是一个组合优化问题。我想我可以首先天真地计算所有可能的索引对 i
和 j
之间的匹配误差,但随后我需要选择最小误差集,然后我不知道我会怎么做。
澄清
IsMatch
函数是自反的(IsMatch(a,b)
暗示 IsMatch(b,a)
),但不具有传递性。然而,它是 3-传递的:IsMatch(a,b) && IsMatch(b,c) && IsMatch(c,d) 隐含 IsMatch(a,d)
。
附录
这个问题显然等同于图论中的最小权完美匹配问题。然而,就我而言,我知道应该有一个“良好”的完美匹配,因此边缘权重的分布不是完全随机的。我觉得应该以某种方式使用这些信息。现在的问题是,对于最小权重完美匹配问题是否有一个好的实现,可以使用我的先验知识在搜索的早期找到解决方案。我也愿意接受任何此类算法的简单实现的指导。
I will phrase the problem in the precise form that I want below:
Given:
Two floating point lists N
and D
of the same length k
(k
is multiple of 2).
It is known that for all i=0,...,k-1
, there exists j != i
such that D[j]*D[i] == N[i]*N[j]
. (I'm using zero-based indexing)
Return:
A (length k/2
) list of pairs (i,j)
such that D[j]*D[i] == N[i]*N[j]
.
The pairs returned may not be unique (any valid list of pairs is okay)
The application for this algorithm is to find reciprocal pairs of eigenvalues of a generalized palindromic eigenvalue problem.
The equality condition is equivalent to N[i]/D[i] == D[j]/N[j]
, but also works when denominators are zero (which is a definite possibility). Degeneracies in the eigenvalue problem cause the pairs to be non-unique.
More generally, the algorithm is equivalent to:
Given:
A list X
of length k
(k
is multiple of 2).
It is known that for all i=0,...,k-1
, there exists j != i
such that IsMatch(X[i],X[j])
returns true, where IsMatch
is a boolean matching function which is guaranteed to return true for at least one j != i
for all i
.
Return:
A (length k/2
) list of pairs (i,j)
such that IsMatch(i,j) == true
for all pairs in the list.
The pairs returned may not be unique (any valid list of pairs is okay)
Obviously, my first problem can be formulated in terms of the second with IsMatch(u,v) := { (u - 1/v) == 0 }
. Now, due to limitations of floating point precision, there will never be exact equality, so I want the solution which minimizes the match error. In other words, assume that IsMatch(u,v)
returns the value u - 1/v
and I want the algorithm to return a list for which IsMatch returns the minimal set of errors. This is a combinatorial optimization problem. I was thinking I can first naively compute the match error between all possible pairs of indexes i
and j
, but then I would need to select the set of minimum errors, and I don't know how I would do that.
Clarification
The IsMatch
function is reflexive (IsMatch(a,b)
implies IsMatch(b,a)
), but not transitive. It is, however, 3-transitive: IsMatch(a,b) && IsMatch(b,c) && IsMatch(c,d)
implies IsMatch(a,d)
.
Addendum
This problem is apparently identically the minimum weight perfect matching problem in graph theory. However, in my case I know that there should be a "good" perfect matching, so the distribution of edge weights is not totally random. I feel that this information should be used somehow. The question now is if there is a good implementation to the min-weight-perfect-matching problem that uses my prior knowledge to arrive at a solution early in the search. I'm also open to pointers towards a simple implementation of any such algorithm.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
好的,我最终使用了
/src/newC/nclMatch.c&q=minimum%20weight%20perfect%20matching%20c_match" rel="nofollow noreferrer">此移植的 Fortran 代码,我只需使用以下 效果很好,而且对于我的目的来说足够快。
Okay, I ended up using this ported Fortran code, where I simply specify the dense upper triangular distance matrix using:
This works great and is fast enough for my purposes.
您应该能够对 (D[i],N[i]) 对进行排序。您不需要除以零 - 您只需相乘即可,如下所示:
然后,扫描排序列表以找到两个分隔点:(N == D) 和 (N == -D);您可以从那里开始匹配互惠对,使用:
作为有效性检查。将 (N == 0) 和 (D == 0) 点留在最后;你认为它们是消极的还是积极的并不重要,因为它们都会相互匹配。
编辑:或者,您可以分别处理 (N==0) 和 (D==0) 情况,将它们从列表中删除。然后,您可以使用 (N[i]/D[i]) 对其余索引进行排序。您可能仍然希望从 1.0 和 -1.0 开始,以确保可以将接近零的情况与完全零的情况相匹配。
You should be able to sort the (D[i],N[i]) pairs. You don't need to divide by zero -- you can just multiply out, as follows:
Then, scan the sorted list to find two separation points: (N == D) and (N == -D); you can start matching reciprocal pairs from there, using:
as a validity check. Leave the (N == 0) and (D == 0) points for last; it doesn't matter whether you consider them negative or positive, as they will all match with each other.
edit: alternately, you could just handle (N==0) and (D==0) cases separately, removing them from the list. Then, you can use (N[i]/D[i]) to sort the rest of the indices. You still might want to start at 1.0 and -1.0, to make sure you can match near-zero cases with exactly-zero cases.
我希望我能解决你的问题。
好吧,如果
IsMatch(i, j) 和 IsMatch(j, l)
则IsMatch(i, l)
。更一般地,IsMatch 关系是传递的、交换的和自反的,即。它是一个等价关系。该算法会转换为列表中出现次数最多的元素(使用 IsMatch 而不是 =)。I hope I got your problem.
Well, if
IsMatch(i, j) and IsMatch(j, l)
thenIsMatch(i, l)
. More generally, theIsMatch
relation is transitive, commutative and reflexive, ie. its an equivalence relation. The algorithm translates to which element appears the most times in the list (use IsMatch instead of =).(如果我理解这个问题...)
这是匹配两个列表中的每对产品的一种方法。
(If I understand the problem...)
Here is one way to match each pair of products in the two lists.
好吧……将每对 D 相乘,并将其与乘积以及构成乘积的元素的下标保存到结构的第二个实例中。
well。。Multiply each pair D and save it to a second instance of the structure with the product, and the subscripts of the elements making up the product.
我刚刚问了我的CS朋友,他提出了下面的算法。他在这里没有帐户(并且显然不愿意创建帐户),但我认为他的答案值得分享。
它依赖于能够计算出图的完美匹配,这是 NP 完全的,但至少它被简化为一个已知的问题。预计该解决方案是 NP 完全的,但这没关系,因为实际上给定列表的大小非常小。我会等待几天更好的答案,或者等待有人扩展如何以合理的方式找到完美的匹配。
I just asked my CS friend, and he came up with the algorithm below. He doesn't have an account here (and apparently unwilling to create one), but I think his answer is worth sharing.
It relies on being able to compute a perfect matching of a graph, which is NP-complete, but at least it is reduced to a known problem. It is expected that the solution be NP-complete, but this is OK since in practice the size of the given lists are quite small. I'll wait around for a better answer for a few days, or for someone to expand on how to find the perfect matching in a reasonable way.
您想要找到 j 使得 D(i)*D(j) = N(i)*N(j) {我假设 * 是普通实数乘法}
假设所有 N(i) 均非零,令
Z(i) = D(i)/N(i)。
问题:找到 j,使得 Z(i) = 1/Z(j)。
将集合分为正数和负数并分别处理。
为了清晰起见,记录日志。 z(i) = log Z(i)。
间接排序。然后,在排序视图中,您应该有类似 -5 -3 -1 +1 +3 +5 的内容。读出 +/- 对,这应该会给你原始索引。
我错过了什么,还是问题很简单?
You want to find j such that D(i)*D(j) = N(i)*N(j) {I assumed * is ordinary real multiplication}
assuming all N(i) are nonzero, let
Z(i) = D(i)/N(i).
Problem: find j, such that Z(i) = 1/Z(j).
Split set into positives and negatives and process separately.
take logs for clarity. z(i) = log Z(i).
Sort indirectly. Then in the sorted view you should have something like -5 -3 -1 +1 +3 +5, for example. Read off +/- pairs and that should give you the original indices.
Am I missing something, or is the problem easy?