首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用Cython包装LAPACKE函数

用Cython包装LAPACKE函数
EN

Stack Overflow用户
提问于 2014-04-21 15:09:13
回答 2查看 689关注 0票数 6

我试图用Cython包装LAPACK函数dgtsv (三对角方程组的求解器)。

我遇到了这个先前的答案,但是由于dgtsv不是封装在scipy.linalg中的LAPACK函数之一,所以我认为我不能使用这种特殊的方法。相反,我一直试图跟踪这个例子

下面是我的lapacke.pxd文件的内容:

代码语言:javascript
复制
ctypedef int lapack_int

cdef extern from "lapacke.h" nogil:

    int LAPACK_ROW_MAJOR
    int LAPACK_COL_MAJOR

    lapack_int LAPACKE_dgtsv(int matrix_order,
                             lapack_int n,
                             lapack_int nrhs,
                             double * dl,
                             double * d,
                             double * du,
                             double * b,
                             lapack_int ldb)

.这是我在_solvers.pyx中的瘦Cython包装器

代码语言:javascript
复制
#!python

cimport cython
from lapacke cimport *

cpdef TDMA_lapacke(double[::1] DL, double[::1] D, double[::1] DU,
                   double[:, ::1] B):

    cdef:
        lapack_int n = D.shape[0]
        lapack_int nrhs = B.shape[1]
        lapack_int ldb = B.shape[0]
        double * dl = &DL[0]
        double * d = &D[0]
        double * du = &DU[0]
        double * b = &B[0, 0]
        lapack_int info

    info = LAPACKE_dgtsv(LAPACK_ROW_MAJOR, n, nrhs, dl, d, du, b, ldb)

    return info

...and这里有一个Python包装器和测试脚本:

代码语言:javascript
复制
import numpy as np
from scipy import sparse
from cymodules import _solvers


def trisolve_lapacke(dl, d, du, b, inplace=False):

    if (dl.shape[0] != du.shape[0] or dl.shape[0] != d.shape[0] - 1
            or b.shape != d.shape):
        raise ValueError('Invalid diagonal shapes')

    if b.ndim == 1:
        # b is (LDB, NRHS)
        b = b[:, None]

    # be sure to force a copy of d and b if we're not solving in place
    if not inplace:
        d = d.copy()
        b = b.copy()

    # this may also force copies if arrays are improperly typed/noncontiguous
    dl, d, du, b = (np.ascontiguousarray(v, dtype=np.float64)
                    for v in (dl, d, du, b))

    # b will now be modified in place to contain the solution
    info = _solvers.TDMA_lapacke(dl, d, du, b)
    print info

    return b.ravel()


def test_trisolve(n=20000):

    dl = np.random.randn(n - 1)
    d = np.random.randn(n)
    du = np.random.randn(n - 1)

    M = sparse.diags((dl, d, du), (-1, 0, 1), format='csc')
    x = np.random.randn(n)
    b = M.dot(x)

    x_hat = trisolve_lapacke(dl, d, du, b)

    print "||x - x_hat|| = ", np.linalg.norm(x - x_hat)

不幸的是,test_trisolve只是在调用_solvers.TDMA_lapacke时出现分段错误。我确信我的setup.py是正确的-- ldd _solvers.so显示_solvers.so在运行时被链接到正确的共享库。

我不知道怎么从这里开始-有什么想法吗?

--一个简短的更新

对于较小的n值,我往往不会立即得到分段错误,但我确实得到了毫无意义的结果(x- x_hat||应该非常接近0):

代码语言:javascript
复制
In [28]: test_trisolve2.test_trisolve(10)
0
||x - x_hat|| =  6.23202576396

In [29]: test_trisolve2.test_trisolve(10)
-7
||x - x_hat|| =  3.88623414288

In [30]: test_trisolve2.test_trisolve(10)
0
||x - x_hat|| =  2.60190676562

In [31]: test_trisolve2.test_trisolve(10)
0
||x - x_hat|| =  3.86631743386

In [32]: test_trisolve2.test_trisolve(10)
Segmentation fault

通常,LAPACKE_dgtsv返回代码0 (这应该表示成功),但偶尔我会得到-7,这意味着参数7 (b)有一个非法的值。正在发生的情况是,实际上只有b的第一个值被修改到位。如果我继续调用test_trisolve,即使n很小,我最终也会遇到分段错误。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-04-21 17:14:24

好的,我终于弄明白了--在这个例子中,我似乎误解了行和列的主要内容。

由于C-连续数组遵循行-主要顺序,我假设我应该指定LAPACK_ROW_MAJOR作为LAPACKE_dgtsv的第一个参数。

事实上,如果我改变了

代码语言:javascript
复制
info = LAPACKE_dgtsv(LAPACK_ROW_MAJOR, ...)

代码语言:javascript
复制
info = LAPACKE_dgtsv(LAPACK_COL_MAJOR, ...)

那么我的功能是:

代码语言:javascript
复制
test_trisolve2.test_trisolve()
0
||x - x_hat|| =  6.67064747632e-12

对我来说,这似乎是违反直觉的,有人能解释一下为什么会这样吗?

票数 4
EN

Stack Overflow用户

发布于 2017-07-01 19:36:40

虽然这个问题相当古老,但似乎仍然是相关的。观察到的行为是对LDB参数的错误解释:

  • Fortran阵列是主要的,阵列B的前导维数对应于N,因此LDB >= max(1,N)。
  • 行大LDB对应于NRHS,因此必须满足LDB >= max(1,NRHS)的条件。

注释b是( LDB,NRHS)不正确,因为b具有维度(LDB,N),在这种情况下LDB应该是1。

从LAPACK_ROW_MAJOR切换到LAPACK_COL_MAJOR解决了这个问题,只要NRHS等于1时。col大调(N, 1 )的内存布局与行大调(1,N)相同。然而,如果NRHS大于1,它将失败。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23200085

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档