给定一些对称整数矩阵列表,我想删除以下等价关系下的所有重复:
如果M1
上有一些排列M2
,则所有s
和{1,...,k}
都有两个kxk矩阵i
,j
是等效的在{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的位置。
答案 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”。
因此算法的草稿是:
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]]
正如评论中所指出的,这只有在矩阵的条目只出现一次时才有效。如果确实发生了多次,但不是经常发生,那么可以通过生成几个等价类来适应这种方法。