将ascii文件中的稀疏矩阵读入python

将ascii文件中的稀疏矩阵读入python,python,sparse-matrix,petsc,Python,Sparse Matrix,Petsc,我有一个使用并行PETSc稀疏矩阵格式的Fortran代码mpaij 我想对这些矩阵做一些分析,所以我想把它们读入python 我尝试了Fortran中的二进制输出和petsc4py中的二进制输入,但显然它们不兼容。Petsc HDF5输出创建了不可读的HDF5文件,因此我现在只能使用ASCII格式 在ascii中,矩阵如下所示: Mat Object: 48 MPI processes type: mpiaij row 0: (0, 0.934865) (1, 0.00582401)

我有一个使用并行PETSc稀疏矩阵格式的Fortran代码
mpaij

我想对这些矩阵做一些分析,所以我想把它们读入python

我尝试了Fortran中的二进制输出和petsc4py中的二进制输入,但显然它们不兼容。Petsc HDF5输出创建了不可读的HDF5文件,因此我现在只能使用ASCII格式

在ascii中,矩阵如下所示:

Mat Object: 48 MPI processes
  type: mpiaij
row 0: (0, 0.934865)  (1, 0.00582401)  (2, -0.00125881)  (3, 0.000157352)  (10, 0.0212704)  (11, -9.37151e-05)  (12, 7.77296e-06)  (13, 1.15276e-06)  (20, -0.00457321)  (21, 9.31045e-06)  (22, -1.37541e-07)  (23, -3.00994e-07)  (30, 0.000571716)  (31, 5.82622e-07)  (32, -2.27908e-07)  (33, 4.55904e-08)  (3410, 0.0005718)  (3411, 3.14914e-06)  (3412, -5.83246e-07)  (3413, 5.58045e-08)  (3420, -0.00457491)  (3421, -3.91645e-05)  (3422, 6.62677e-06)  (3423, -5.10165e-07)  (3430, 0.0212818)  (3431, 0.000230778)  (3432, -3.75686e-05)  (3433, 2.57173e-06) 
row 1: (...)

有没有一种优雅的方法可以将其解析为python?

我不熟悉PETSc或其矩阵格式,但给定示例ASCII格式,当然可以将其转换为python中的任何其他矩阵格式。我假设该文件包含每个非零行的一行,并且每行中的数字对是列索引和相应的数字。对吗

你认为“优雅的方式”是个人的观点,对于堆栈溢出不是一个有效的问题,但是我可以试着指出一个工作解决方案的正确方向。

首先,在不知道所有细节的情况下,我认为正确的问题应该是“为什么Fortran中的二进制输出和petsc4py中的二进制输入不兼容?”如果你能解决这个问题,那可能是最好的解决方案。如果我没记错的话,Fortran代码支持不同的字节顺序,默认情况下可能使用大端格式,而Python通常使用小端格式。您可以在其中一个库函数中指定字节顺序,或者在必要时手动转换字节顺序。这可能是您首先要研究的问题

作为一种解决方法,您可以用Python解析ASCII格式以进行进一步处理。我假设您已经搜索了现有库,但找不到任何库,因此需要编写一些自定义代码。根据您的需要,“好”的解决方案将使用正则表达式,但一种快速而肮脏的方法是使用标准字符串方法和
eval()
函数,因为ASCII格式已经非常类似于Python语法:-)

注意:仅当您信任输入文件时才使用
eval()
函数,因为它容易受到代码注入攻击!对于个人使用,这通常不是问题

下面我提供了一些示例代码。这将完成基本的输入处理。如何处理数据取决于您自己,因此您需要自己完成代码。这个示例代码只是打印数字

def read\u mpaij(文件):
lines=file.read().splitlines()
在[0]行中断言“Mat Object:”
断言行[1]=“类型:mpaij”
对于行中的行[2:]:
零件=行。拆分(“:”)
断言长度(部分)=2
断言部分[0]。StartWith('行')
行索引=int(部分[0][4:])
行内容=eval(部分[1]。替换(')('),'),('))
#这里有行索引和元组(列索引,值)
#指定非零内容的对。你可以处理这个
#根据您的需要,例如,将值存储在数组中。
对于行内容中的(列索引,值):
打印('行%d,列%d:%s'(行索引,列索引,值))
#TODO:在这里实现真正的代码。
#您可能希望执行以下操作:
#数据[行索引][列索引]=值
def main():
以open('input.txt','rt',encoding='ascii')作为文件:
读取(文件)
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
main()
输出:

第0行第0列:0.934865
第0行第1列:0.00582401
第0行第2列:-0.00125881
第0行第3列:0.000157352
第0行第10列:0.021274
第0行第11列:-9.37151e-05
第0行第12列:7.77296e-06
第0行第13列:1.15276e-06
第0行第20列:-0.00457321
第0行第21列:9.31045e-06
第0行第22列:-1.37541e-07
第0行第23列:-3.00994e-07
第0行第30列:0.000571716
第0行第31列:5.82622e-07
第0行第32列:-2.27908e-07
第0行第33列:4.55904e-08
第0行第3410列:0.0005718
第0行第3411列:3.14914e-06
第0行第3412列:-5.83246e-07
第0行第3413列:5.58045e-08
第0行第3420列:-0.00457491
第0行第3421列:-3.91645e-05
第0行第3422列:6.62677e-06
第0行第3423列:-5.10165e-07
第0行第3430列:0.0212818
第0行第3431列:0.000230778
第0行第3432列:-3.75686e-05
第0行第3433列:2.57173e-06
...

正则表达式是你的朋友。比如说:

for recnum, rec in enumerate(fh.readlines()):
    mat = re.match(r'row\s*(\d+):\s*(.*)', rec)
    if (not mat): raise IOError("Bad data at rec %d." % (recnum))
    rowNum = int(mat.group(1))
    rest = mat.group(2)
    lastColNum = -1
    for col in re.finditer(r'\(\d+),\s*(\d+\.\d*\)', rest):
        colNum = int(mat.group(1))
        if (colNum <= lastColNum):
            raise KeyError("colNum out of order at rec %d." % (colNum, recNum))
        value = float(mat.group(2))
        # save cell, like via numpy tbl[rowNum, colNum] = value
对于recnum,枚举中的rec(fh.readlines()):
mat=re.match(r'row\s*(\d+):\s*(.*),rec)
if(非mat):引发IOError(“记录%d.”%处的错误数据(记录数量))
rowNum=int(材料组(1))
剩余=材料组(2)
lastColNum=-1
对于re.finditer(r'\(\d+)\s*(\d+\.\d*)'中的列,rest):
colNum=int(材料组(1))
if(colNum)