Python 努比&x2018;智能&x2019;对称矩阵

Python 努比&x2018;智能&x2019;对称矩阵,python,matrix,numpy,Python,Matrix,Numpy,numpy中是否有一个智能且节省空间的对称矩阵,当写入[i][j]时,它会自动(透明)填充[j][i]位置 import numpy a = numpy.symmetric((3, 3)) a[0][1] = 1 a[1][0] == a[0][1] # True print(a) # [[0 1 0], [1 0 0], [0 0 0]] assert numpy.all(a == a.T) # for any symmetric matrix 自动Hermitian也很好,尽管我在撰写本

numpy中是否有一个智能且节省空间的对称矩阵,当写入
[i][j]
时,它会自动(透明)填充
[j][i]
位置

import numpy
a = numpy.symmetric((3, 3))
a[0][1] = 1
a[1][0] == a[0][1]
# True
print(a)
# [[0 1 0], [1 0 0], [0 0 0]]

assert numpy.all(a == a.T) # for any symmetric matrix

自动Hermitian也很好,尽管我在撰写本文时不需要它。

如果您能够在计算之前对矩阵进行对称化,那么以下速度应该相当快:

def symmetrize(a):
    """
    Return a symmetrized version of NumPy array a.

    Values 0 are replaced by the array value at the symmetric
    position (with respect to the diagonal), i.e. if a_ij = 0,
    then the returned array a' is such that a'_ij = a_ji.

    Diagonal values are left untouched.

    a -- square NumPy array, such that a_ij = 0 or a_ji = 0, 
    for i != j.
    """
    return a + a.T - numpy.diag(a.diagonal())
这是在合理的假设下工作的(例如在运行对称化之前不同时执行
a[0,1]=42
和矛盾的
a[1,0]=123

如果你真的需要一个透明的对称化,你可以考虑子类NUMYP.NDARRY,并简单地重新定义<代码>

class SymNDArray(numpy.ndarray):
    """
    NumPy array subclass for symmetric matrices.

    A SymNDArray arr is such that doing arr[i,j] = value
    automatically does arr[j,i] = value, so that array
    updates remain symmetrical.
    """

    def __setitem__(self, (i, j), value):
        super(SymNDArray, self).__setitem__((i, j), value)                    
        super(SymNDArray, self).__setitem__((j, i), value)                    

def symarray(input_array):
    """
    Return a symmetrized version of the array-like input_array.

    The returned array has class SymNDArray. Further assignments to the array
    are thus automatically symmetrized.
    """
    return symmetrize(numpy.asarray(input_array)).view(SymNDArray)

# Example:
a = symarray(numpy.zeros((3, 3)))
a[0, 1] = 42
print a  # a[1, 0] == 42 too!
(或根据您的需要,使用矩阵代替数组的等效项)。这种方法甚至可以处理更复杂的赋值,比如
a[:,1]=-1
,它可以正确地设置
a[1,:]
元素


请注意,Python3消除了编写
def…(…,(i,j),…)
的可能性,因此在使用Python3运行之前,必须稍微调整代码:
def\uu setitem\uuuuuu(self,indexes,value):(i,j)=index

numpy中对称矩阵的优化处理这一更普遍的问题也让我感到困扰

在研究之后,我认为答案可能是numpy在某种程度上受到对称矩阵的基础BLAS例程所支持的内存布局的限制

虽然一些BLAS例程确实利用对称性来加速对称矩阵的计算,但它们仍然使用与完整矩阵相同的内存结构,即
n^2
空间,而不是
n(n+1)/2
。只是他们被告知矩阵是对称的,并且只使用上下三角形中的值

一些
scipy.linalg
例程确实接受传递给BLAS例程的标志(如
linalg.solve
上的
sym_pos=True
),尽管在numpy中对此提供更多支持会更好,特别是DSYRK(对称秩k更新)之类的例程的包装器,这将允许一个Gram矩阵的计算速度比dot(M.T,M)快一点


(可能担心在时间和/或空间上优化2倍常数因子似乎有些吹毛求疵,但这可能会改变你在一台机器上可以处理多大问题的阈值…

这是简单的python,而不是numpy,但我只是创建了一个例程来填充它 对称矩阵(以及确保其正确性的测试程序):

随机导入
#用成本填充对称矩阵(即m[x][y]==m[y][x]
#出于演示目的,此例程将每个节点连接到所有其他节点
#由于矩阵存储成本,因此使用数字表示节点
#因此,行和列索引可以表示节点
def fillCostMatrix(dim):#阵列的方形阵列
#创建零矩阵
新的_平方=[[0表示范围内的行(dim)]表示范围内的列(dim)]
#填写主对角线
对于范围内的v(0,尺寸):
新的平方[v][v]=随机的随机范围(1,10)
#通过对角复制对称填充上下三角形
对于范围内的v(1,尺寸):
迭代次数=dim-v
x=v
y=0
当迭代次数>0时:
new_square[x][y]=new_square[y][x]=random.randrange(1,10)
x+=1
y+=1
迭代次数-=1
返回新奥尔良广场
#健全测试
def测试_对称性(方形):
尺寸=透镜(平方[0])
isSymmetric=''
对于范围内的x(0,尺寸):
对于范围内的y(0,变暗):
如果平方[x][y]!=平方[y][x]:
isSymmetric='不'
打印“矩阵为”,对称,“对称”
def showSquare(方形):
#打印出方阵
columnHeader=“”
对于范围内的i(len(square)):
columnHeader+=''+str(一)
打印列标题
i=0;
对于广场中的col:
打印i、列#打印行号和数据
i+=1
def myMain(argv):
如果len(argv)==1:
nodeCount=6
其他:
尝试:
nodeCount=int(argv[1])
除:
打印“参数必须是数字”
退出

#keep nodeCount存储对称矩阵有许多众所周知的方法,因此它们不需要占用n^2个存储元素。此外,重写常用操作以访问这些修改后的存储方式是可行的。最终的工作是Golub和Van Loan,《矩阵计算》,1996年第3版,约翰·霍普金斯大学出版社,第1.27-1.2.9节。例如,从形式(1.2.2)中引用它们,在对称矩阵中只需要存储
a=[a{i,j}]
i>=j
。然后,假设持有矩阵的向量表示为V,并且a是n×n,将
a{i,j}
放入

V[(j-1)n - j(j-1)/2 + i]
这假定为1-1索引

Golub和Van Loan提供了算法1.2.3,该算法显示了如何访问存储的V来计算
y=vx+y


Golub和Van Loan还提供了一种以对角占优形式存储矩阵的方法。这不会节省存储空间,但支持对某些其他类型的操作进行随时访问。

如果
[j][i]以pythonical方式填写
[i][j]
则很容易
已填充。存储问题有点有趣。可以使用
packed
属性扩充numpy数组类,该属性对保存存储和以后读取数据都很有用

class Sym(np.ndarray):

    # wrapper class for numpy array for symmetric matrices. New attribute can pack matrix to optimize storage.
    # Usage:
    # If you have a symmetric matrix A as a shape (n,n) numpy ndarray, Sym(A).packed is a shape (n(n+1)/2,) numpy array 
    # that is a packed version of A.  To convert it back, just wrap the flat list in Sym().  Note that Sym(Sym(A).packed)


    def __new__(cls, input_array):
        obj = np.asarray(input_array).view(cls)

        if len(obj.shape) == 1:
            l = obj.copy()
            p = obj.copy()
            m = int((np.sqrt(8 * len(obj) + 1) - 1) / 2)
            sqrt_m = np.sqrt(m)

            if np.isclose(sqrt_m, np.round(sqrt_m)):
                A = np.zeros((m, m))
                for i in range(m):
                    A[i, i:] = l[:(m-i)]
                    A[i:, i] = l[:(m-i)]
                    l = l[(m-i):]
                obj = np.asarray(A).view(cls)
                obj.packed = p

            else:
                raise ValueError('One dimensional input length must be a triangular number.')

        elif len(obj.shape) == 2:
            if obj.shape[0] != obj.shape[1]:
                raise ValueError('Two dimensional input must be a square matrix.')
            packed_out = []
            for i in range(obj.shape[0]):
                packed_out.append(obj[i, i:])
            obj.packed = np.concatenate(packed_out)

        else:
            raise ValueError('Input array must be 1 or 2 dimensional.')

        return obj

    def __array_finalize__(self, obj):
        if obj is None: return
        self.packed = getattr(obj, 'packed', None)

```

要构造沿主对角线对称且主对角线上有0的NxN矩阵,可以执行以下操作:

a = np.array([1, 2, 3, 4, 5])
b = np.zeros(shape=(a.shape[0], a.shape[0]))
upper = np.triu(b + a)
lower = np.tril(np.transpose(b + a))
D = (upper + lower) * (np.full(a.shape[0], fill_value=1) - np.eye(a.shape[0]))
这是一种特殊情况,但最近我用这种矩阵表示网络邻接

希望有帮助。
干杯。

你可以考虑把答案标记为“接受,如果它解决了你的问题。”:我想等待更好的(即内置和内存效率)。
a = np.array([1, 2, 3, 4, 5])
b = np.zeros(shape=(a.shape[0], a.shape[0]))
upper = np.triu(b + a)
lower = np.tril(np.transpose(b + a))
D = (upper + lower) * (np.full(a.shape[0], fill_value=1) - np.eye(a.shape[0]))