在 Python 中调用 Pardiso 6
Calling Pardiso 6 in Python
我正在尝试在 Python 中使用 Pardiso 6 稀疏求解器库。问题是我似乎无法加载 Pardiso shared object (SO)。这是我在调用
时遇到的错误
import ctypes
pardiso = ctypes.CDLL(pardiso_so_address)
Traceback (most recent call last):
File "test.py", line 27, in <module>
pardiso = ctypes.CDLL(lib720)
File "/home/amin/anaconda3/envs/idp/lib/python3.7/ctypes/__init__.py", line 364, in __init__
self._handle = _dlopen(self._name, mode)
OSError: ./libpardiso600-GNU720-X86-64.so: undefined symbol: sgetrf_
如果有人能对此有所说明,我将不胜感激。
PS。我已经联系了 Pardiso 开发人员,他们告诉我我需要 link 针对优化的 BLAS,但我已经通过 conda
.
安装了 MKL
更新 1:我通过 conda
安装了 mkl
,但没有用。 St运行gely,我将 import scipy
添加到 header 并且错误消失了。如果我添加 import mkl
,也会发生同样的事情。因此,出于某种原因,除非手动导入 scipy
或 mkl
,否则 .so
不知道 lapack
安装存在。无论如何,现在抛出另一个错误,我认为这可能与 libgfortran
库有关。这是错误
Traceback (most recent call last):
File "test.py", line 34, in <module>
pardiso = ctypes.CDLL(lib720)
File "/home/amin/anaconda3/envs/test/lib/python3.7/ctypes/__init__.py", line 364, in __init__
self._handle = _dlopen(self._name, mode)
OSError: ./libpardiso600-GNU720-X86-64.so: undefined symbol: _gfortran_st_close
我double-checked看看是否安装了libgfortran
,果然是:
(test) PyPardisoProject$ ldconfig -p | grep libgfortran
libgfortran.so.5 (libc6,x86-64) => /lib/x86_64-linux-gnu/libgfortran.so.5
libgfortran.so.4 (libc6,x86-64) => /lib/x86_64-linux-gnu/libgfortran.so.4
我认为类似的事情可能在起作用,即库在那里但需要被触发(类似于 import scipy
似乎为 liblapack
所做的,但我不知道我怎么触发它。
注意:我在 Pardiso 网站上找到了一个 C 语言的例子,并通过
测试了 .so
文件
$ gcc pardiso_sym.c -o pardiso_sym -L . -lpardiso600-GNU720-X86-64 -llapack -fopenmp -lgfortran
$ OMP_NUM_THREADS=1 ./pardiso_sym
它没有问题(使用我机器上的现有库)。所以,.so
有效,只是我不知道如何在 Python.
中告知它的依赖关系
更新 2:这是 ldd pardiso_sym
的输出:
Scripts$ ldd pardiso_sym
linux-vdso.so.1 (0x00007ffe7e982000)
libpardiso600-GNU720-X86-64.so (0x00007f326802d000)
liblapack.so.3 => /lib/x86_64-linux-gnu/liblapack.so.3 (0x00007f3267976000)
libgfortran.so.4 => /lib/x86_64-linux-gnu/libgfortran.so.4 (0x00007f3267795000)
libgomp.so.1 => /lib/x86_64-linux-gnu/libgomp.so.1 (0x00007f326775b000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3267568000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f3267545000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f32673f6000)
/lib64/ld-linux-x86-64.so.2 (0x00007f32685df000)
libblas.so.3 => /lib/x86_64-linux-gnu/libblas.so.3 (0x00007f3267389000)
libgfortran.so.5 => /lib/x86_64-linux-gnu/libgfortran.so.5 (0x00007f32670e9000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f32670cf000)
libquadmath.so.0 => /lib/x86_64-linux-gnu/libquadmath.so.0 (0x00007f3267083000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f326707d000)
所以,我添加了公共路径,即 /lib/x86_64-linux-gnu
和 /lib64
到 PATH
和 运行 Python 脚本再次通过:
PATH=$PATH:/lib/x86_64-linux-gnu:/lib64 python padiso_script.py
但是报同样的错误。我也尝试添加到 LD_LIBRARY_PATH
,但也没有用。
Pardiso 6 sparse solver
至少 sgetrf
依赖于 Lapack 函数,它使用带行交换的部分旋转计算一般 M×N 矩阵 A 的 LU 分解。
根据我们的阅读,libpardiso600-GNU720-X86-64.so
与共享的 Lapack 库动态链接。您需要提供一个包含一个实现的路径。
在启动 Python 之前,我建议您使用 LD_LIBRARY_PATH
并包含您正在使用的 BLAS/Lapack 库的路径。它可以是 netlib 实现、ATLAS 实现或 MKL 实现。
LD_LIRARY_PATH=$LD_LIRARY_PATH:/my_path_to_lapack \
python -c"import ctypes; pardiso = ctypes.CDLL(pardiso_so_address)"
如果使用conda
,可以用命令安装
conda install -c anaconda mkl
这种情况,安装可能直接解决问题
Pardiso 6 和 Intel MKL Pardiso 不兼容,因为它们具有不同的 API。您可以尝试从系统路径中删除 MKL,添加 OpenBLAS,然后再次尝试 link 您的示例。
诀窍是,不是将依赖项的位置添加到系统 PATH
s,而是需要显式加载依赖项,即 lapack
、blas
和 gfortran
在加载 Pardiso 库之前在 Python 脚本中。此外,您必须显式地将可选的 mode=ctypes.RLTD_GLOBAL
参数传递给 ctypes.CDLL
方法,以便使依赖项可以全局访问,因此 Pardiso 可以访问它们。
import ctypes
import ctypes.util
shared_libs = ["lapack", "blas", "omp", "gfortran"]
for lib in shared_libs:
# Fetch the proper name of the dependency
libname = ctypes.util.find_library(lib)
# Load the dependency and make it globally accessible
ctypes.CDLL(libname, mode=ctypes.RTLD_GLOBAL)
# Finally, load the Pardiso library
pardiso = ctypes.CDLL(pardiso_so_address)
根据我的经验,如果您在安装了 mkl
的 conda
环境中,您只需将 gfortran
列为依赖项,其余部分将自动加载和访问,在哪个案例集 shared_libs = ["gfortran"]
.
我正在尝试在 Python 中使用 Pardiso 6 稀疏求解器库。问题是我似乎无法加载 Pardiso shared object (SO)。这是我在调用
时遇到的错误import ctypes
pardiso = ctypes.CDLL(pardiso_so_address)
Traceback (most recent call last):
File "test.py", line 27, in <module>
pardiso = ctypes.CDLL(lib720)
File "/home/amin/anaconda3/envs/idp/lib/python3.7/ctypes/__init__.py", line 364, in __init__
self._handle = _dlopen(self._name, mode)
OSError: ./libpardiso600-GNU720-X86-64.so: undefined symbol: sgetrf_
如果有人能对此有所说明,我将不胜感激。
PS。我已经联系了 Pardiso 开发人员,他们告诉我我需要 link 针对优化的 BLAS,但我已经通过 conda
.
更新 1:我通过 conda
安装了 mkl
,但没有用。 St运行gely,我将 import scipy
添加到 header 并且错误消失了。如果我添加 import mkl
,也会发生同样的事情。因此,出于某种原因,除非手动导入 scipy
或 mkl
,否则 .so
不知道 lapack
安装存在。无论如何,现在抛出另一个错误,我认为这可能与 libgfortran
库有关。这是错误
Traceback (most recent call last):
File "test.py", line 34, in <module>
pardiso = ctypes.CDLL(lib720)
File "/home/amin/anaconda3/envs/test/lib/python3.7/ctypes/__init__.py", line 364, in __init__
self._handle = _dlopen(self._name, mode)
OSError: ./libpardiso600-GNU720-X86-64.so: undefined symbol: _gfortran_st_close
我double-checked看看是否安装了libgfortran
,果然是:
(test) PyPardisoProject$ ldconfig -p | grep libgfortran
libgfortran.so.5 (libc6,x86-64) => /lib/x86_64-linux-gnu/libgfortran.so.5
libgfortran.so.4 (libc6,x86-64) => /lib/x86_64-linux-gnu/libgfortran.so.4
我认为类似的事情可能在起作用,即库在那里但需要被触发(类似于 import scipy
似乎为 liblapack
所做的,但我不知道我怎么触发它。
注意:我在 Pardiso 网站上找到了一个 C 语言的例子,并通过
测试了.so
文件
$ gcc pardiso_sym.c -o pardiso_sym -L . -lpardiso600-GNU720-X86-64 -llapack -fopenmp -lgfortran
$ OMP_NUM_THREADS=1 ./pardiso_sym
它没有问题(使用我机器上的现有库)。所以,.so
有效,只是我不知道如何在 Python.
更新 2:这是 ldd pardiso_sym
的输出:
Scripts$ ldd pardiso_sym
linux-vdso.so.1 (0x00007ffe7e982000)
libpardiso600-GNU720-X86-64.so (0x00007f326802d000)
liblapack.so.3 => /lib/x86_64-linux-gnu/liblapack.so.3 (0x00007f3267976000)
libgfortran.so.4 => /lib/x86_64-linux-gnu/libgfortran.so.4 (0x00007f3267795000)
libgomp.so.1 => /lib/x86_64-linux-gnu/libgomp.so.1 (0x00007f326775b000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3267568000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f3267545000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f32673f6000)
/lib64/ld-linux-x86-64.so.2 (0x00007f32685df000)
libblas.so.3 => /lib/x86_64-linux-gnu/libblas.so.3 (0x00007f3267389000)
libgfortran.so.5 => /lib/x86_64-linux-gnu/libgfortran.so.5 (0x00007f32670e9000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f32670cf000)
libquadmath.so.0 => /lib/x86_64-linux-gnu/libquadmath.so.0 (0x00007f3267083000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f326707d000)
所以,我添加了公共路径,即 /lib/x86_64-linux-gnu
和 /lib64
到 PATH
和 运行 Python 脚本再次通过:
PATH=$PATH:/lib/x86_64-linux-gnu:/lib64 python padiso_script.py
但是报同样的错误。我也尝试添加到 LD_LIBRARY_PATH
,但也没有用。
Pardiso 6 sparse solver
至少 sgetrf
依赖于 Lapack 函数,它使用带行交换的部分旋转计算一般 M×N 矩阵 A 的 LU 分解。
根据我们的阅读,libpardiso600-GNU720-X86-64.so
与共享的 Lapack 库动态链接。您需要提供一个包含一个实现的路径。
在启动 Python 之前,我建议您使用 LD_LIBRARY_PATH
并包含您正在使用的 BLAS/Lapack 库的路径。它可以是 netlib 实现、ATLAS 实现或 MKL 实现。
LD_LIRARY_PATH=$LD_LIRARY_PATH:/my_path_to_lapack \
python -c"import ctypes; pardiso = ctypes.CDLL(pardiso_so_address)"
如果使用conda
,可以用命令安装
conda install -c anaconda mkl
这种情况,安装可能直接解决问题
Pardiso 6 和 Intel MKL Pardiso 不兼容,因为它们具有不同的 API。您可以尝试从系统路径中删除 MKL,添加 OpenBLAS,然后再次尝试 link 您的示例。
诀窍是,不是将依赖项的位置添加到系统 PATH
s,而是需要显式加载依赖项,即 lapack
、blas
和 gfortran
在加载 Pardiso 库之前在 Python 脚本中。此外,您必须显式地将可选的 mode=ctypes.RLTD_GLOBAL
参数传递给 ctypes.CDLL
方法,以便使依赖项可以全局访问,因此 Pardiso 可以访问它们。
import ctypes
import ctypes.util
shared_libs = ["lapack", "blas", "omp", "gfortran"]
for lib in shared_libs:
# Fetch the proper name of the dependency
libname = ctypes.util.find_library(lib)
# Load the dependency and make it globally accessible
ctypes.CDLL(libname, mode=ctypes.RTLD_GLOBAL)
# Finally, load the Pardiso library
pardiso = ctypes.CDLL(pardiso_so_address)
根据我的经验,如果您在安装了 mkl
的 conda
环境中,您只需将 gfortran
列为依赖项,其余部分将自动加载和访问,在哪个案例集 shared_libs = ["gfortran"]
.