如何根据某种等价关系从矩阵列表中删除重复项?

时间:2017-08-17 13:13:46

标签: python numpy

给定一些对称整数矩阵列表,我想删除以下等价关系下的所有重复:

如果M1上有一些排列M2,则所有s{1,...,k}都有两个kxk矩阵ij是等效的在{1,...,k}我们有M1_ij = M2_s(i)s(j),即两个矩阵是"相等"如果我可以通过同时排列其行和列来从另一个中获取一个。

不幸的是,我的天真方法(在构建列表时,检查新矩阵的任何排列是否已经在列表中)证明太慢了。

我可以想到的一些可能更快的替代方案是将所有矩阵放在列表中,将它们置换为某些"规范排列"然后删除所述的重复项,例如, here。但是,我不确定如何实现这样的规范排列"在代码中。

要进一步缩小此范围:矩阵相对较小(k <= 4),列表将包含大约5或6位数的矩阵,并且矩阵的dtype必须是某个整数类型(目前为intc,但我可以更改)。

最终列表的顺序无关紧要,每个等价类的哪个代表也不存在。如果需要,整个过程可能需要一些小时,但不是几天。

是否有一些合理有效的方法来实现这一目标?我(又一次)是否错过了一些很酷的NumPy或SciPy设施,可以帮助我解决这个问题?

根据要求,一些小例子来说明等价关系如何运作:

矩阵{{1,1,1},{1,2,0},{1,0,3}}{{1,1,1},{1,3,0},{1,0,2}}是等效的,因为排列{1,2,3}->{1,3,2}会将一个转换为另一个。

矩阵{{1,1,1},{1,2,0},{1,0,3}}{{1,1,0},{1,2,1},{0,1,3}}不等价,你不能在没有置换对角线的情况下改变1的位置。

3 个答案:

答案 0 :(得分:3)

这是一个代数答案。我怀疑应该有一个更令人满意的组合答案。

如果存在permutation matrix P使得M'= P ^ { - 1} M P,则说两个矩阵M和M'是等价的。

让我们使用M和M'的特征分解:

M = Q ^ { - 1} D Q

M = Q'^ { - 1} D'Q'

其中D和D'是包含特征值的对角矩阵,Q和Q'是正交矩阵。

我们可以将相等重写为:

D = D'直到排列(即两个矩阵应具有相同的特征值

Q'= PQ

第二个条件的测试很容易。鉴于Q是正交的,它等于检查矩阵点(Q,Q'.T)是否是置换矩阵,即它是否每行和每列只有一个“1”。

因此算法的草稿是:

  • 拿M和M'
  • 计算M和M'的特征分解(Q,D)和(Q',D')(使用np.linalg.eigh)
  • 如果它们没有相同的特征值(当然达到数值精度),它们就不相同了
  • 否则,计算np.dot(Q, Q'.T)并测试它是否为置换矩阵

我认为瓶颈是特征分解,但每个矩阵只需要做一次。希望第一次测试能够快速丢弃很多矩阵。

希望这有帮助。

答案 1 :(得分:2)

您可以将矩阵视为表示图形的邻接/权重矩阵,然后测试两个图形是否彼此同构。 networkx具有方便的功能(可以通过pip安装)。

import numpy as np
import networkx as nx
from networkx.algorithms.isomorphism import numerical_edge_match

# create matrices
n = 4
a = np.random.randint(0, 10, size=(n,n))
a = a + a.T # i.e. symmetric
b = np.rot90(a, k=2) # i.e. a rotated by 180 degrees
c = np.ones((n,n), dtype=np.int) # counter-example

# create graphs
ga = nx.from_numpy_matrix(a)
gb = nx.from_numpy_matrix(b)
gc = nx.from_numpy_matrix(c)

# test if isomorphic
print "a isomorphic with b:", nx.is_isomorphic(ga, gb, edge_match=numerical_edge_match('weight', 1)) # True
print "a isomorphic with c:", nx.is_isomorphic(ga, gc, edge_match=numerical_edge_match('weight', 1)) # False

答案 2 :(得分:-1)

只需使用您的规范方法即可。 搜索矩阵中的最大条目,将其放在右上角。 然后根据它的条目对第一列和第一行进行排序。

A = np.array([[1,2,3,5],
     [3,6,2,6],
     [3,5,7,2],
     [1,3,6,3]])
a = np.where(A == np.amax(A))
sort_colums = np.argsort(A[a[0]].ravel())[::-1]
sort_rows = np.argsort(A[:,a[1]].ravel())[::-1]
Col_sorted = A[:,sort_colums]
Equiv_class = Col_sorted[sort_rows]
#returns [[7, 5, 3, 2],
          [6, 3, 1, 3],
          [3, 2, 1, 5],
          [2, 6, 3, 6]]

正如评论中所指出的,这只有在矩阵的条目只出现一次时才有效。如果确实发生了多次,但不是经常发生,那么可以通过生成几个等价类来适应这种方法。