首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >2D MemoryView转C指针错误(1D有效,但2D不起作用)

2D MemoryView转C指针错误(1D有效,但2D不起作用)
EN

Stack Overflow用户
提问于 2015-07-15 05:17:21
回答 2查看 243关注 0票数 1

我可以使用this StackOverflow error获得1D内存视图的指针,但将相同的方法应用于2D内存视图会给我一个“无法将类型'double *‘赋给'double **'”的错误。

代码语言:javascript
运行
复制
cdef extern from "dgesvd.h" nogil:
    void dgesvd(double **A, int m, int n, double *S, double **U, double **VT)


cdef:
    double[:] S
    double[:,:] A, U, VT

A = np.ascontiguousarray(np.zeros((N,N)))
S = np.zeros(N)
U = np.zeros(N)
VT = np.zeros(N)

dgesvd(&A[0,0], N, N, &S[0], &U[0], &VT[0])

编辑:我通过这样做来编译它。

因此,我通过执行以下操作使其成功编译:

代码语言:javascript
运行
复制
    cdef:
        double[:] S
        double[:,:] A, U, VT

    U = np.zeros((N,N))
    VT = np.zeros((N,N))
    A = np.zeros((N,N))
    S = np.zeros(N)

    A_p = <double *> malloc(sizeof(double) * N)
    U_p = <double *> malloc(sizeof(double) * N)
    VT_p = <double *> malloc(sizeof(double) * N)

    for i in range(N):
        A_p = &A[i, 0]
        U_p = &U[i, 0]
        VT_p = &VT[i, 0]

    dgesvd(&A_p, N, N, &S[0], &U_p, &VT_p)

    free(A_p)
    free(U_p)
    free(VT_p)

但是当我尝试运行它时,我得到了一个段错误,所以我可能做错了。

以下是"dgesvd.h“的内容(我没有写它,但我知道它是有效的):

代码语言:javascript
运行
复制
/*
  This file has my implementation of the LAPACK routine dgesdd for
  C++.  This program solves for the singular value decomposition of a
  rectangular matrix A.  The function call is of the form

    void dgesdd(double **A, int m, int n, double *S, double *U, double *VT)

    A: the m by n matrix that we are decomposing
    m: the number of rows in A
    n: the number of columns in A (generally, n<m)
    S: a min(m,n) element array to hold the singular values of A
    U: a [m, min(m,n)] element rectangular array to hold the right
       singular vectors of A.  These vectors will be the columns of U,
       so that U[i][j] is the ith element of vector j.
    VT: a [min(m,n), n] element rectangular array to hold the left
        singular vectors of A.  These vectors will be the rows of VT
    (it is a transpose of the vector matrix), so that VT[i][j] is
    the jth element of vector i.

  Note that S, U, and VT must be initialized before calling this
  routine, or there will be an error.  Here is a quick sample piece of
  code to perform this initialization; in many cases, it can be lifted
  right from here into your program.

    S = new double[minmn];
    U = new double*[m]; for (int i=0; i<m; i++) U[i] = new double[minmn];
    VT = new double*[minmn]; for (int i=0; i<minmn; i++) VT[i] = new double[n];

  Scot Shaw
  24 January 2000 */

void dgesvd(double **A, int m, int n, double *S, double **U, double **VT);

double *dgesvd_ctof(double **in, int rows, int cols);
void dgesvd_ftoc(double *in, double **out, int rows, int cols);

extern "C" void dgesvd_(char *jobu, char *jobvt, int *m, int *n,
            double *a, int *lda, double *s, double *u,
            int *ldu, double *vt, int *ldvt, double *work,
            int *lwork, int *info);

void dgesvd(double **A, int m, int n, double *S, double **U, double **VT)
{
  char jobu, jobvt;
  int lda, ldu, ldvt, lwork, info;
  double *a, *u, *vt, *work;

  int minmn, maxmn;

  jobu = 'S'; /* Specifies options for computing U.
         A: all M columns of U are returned in array U;
         S: the first min(m,n) columns of U (the left
            singular vectors) are returned in the array U;
         O: the first min(m,n) columns of U (the left
            singular vectors) are overwritten on the array A;
         N: no columns of U (no left singular vectors) are
            computed. */

  jobvt = 'S'; /* Specifies options for computing VT.
          A: all N rows of V**T are returned in the array
             VT;
          S: the first min(m,n) rows of V**T (the right
             singular vectors) are returned in the array VT;
          O: the first min(m,n) rows of V**T (the right
             singular vectors) are overwritten on the array A;
          N: no rows of V**T (no right singular vectors) are
             computed. */

  lda = m; // The leading dimension of the matrix a.
  a = dgesvd_ctof(A, lda, n); /* Convert the matrix A from double pointer
              C form to single pointer Fortran form. */

  ldu = m;

  /* Since A is not a square matrix, we have to make some decisions
     based on which dimension is shorter. */

  if (m>=n) { minmn = n; maxmn = m; } else { minmn = m; maxmn = n; }

  ldu = m; // Left singular vector matrix
  u = new double[ldu*minmn];

  ldvt = minmn; // Right singular vector matrix
  vt = new double[ldvt*n];

  lwork = 5*maxmn; // Set up the work array, larger than needed.
  work = new double[lwork];

  dgesvd_(&jobu, &jobvt, &m, &n, a, &lda, S, u,
      &ldu, vt, &ldvt, work, &lwork, &info);

  dgesvd_ftoc(u, U, ldu, minmn);
  dgesvd_ftoc(vt, VT, ldvt, n);

  delete a;
  delete u;
  delete vt;
  delete work;
}

double* dgesvd_ctof(double **in, int rows, int cols)
{
  double *out;
  int i, j;

  out = new double[rows*cols];
  for (i=0; i<rows; i++) for (j=0; j<cols; j++) out[i+j*rows] = in[i][j];
  return(out);
}

void dgesvd_ftoc(double *in, double **out, int rows, int cols)
{
  int i, j;

  for (i=0; i<rows; i++) for (j=0; j<cols; j++) out[i][j] = in[i+j*rows];
}
EN

回答 2

Stack Overflow用户

发布于 2015-07-15 15:48:38

你不想使用“指针到指针”的形式。所有的Cython/numpy数组都存储为一个连续的数组,以及一些长度参数,以便进行2D访问。最好是在Cython语言中复制dgesvd包装器(分配工作数组,但不进行ftocctof转换)。

我已经试过了,在下面,但它是未经测试的,所以可能有bug。它更多的是关于要做什么的要点,而不是被直接复制。

代码语言:javascript
运行
复制
def dgesvd(double [:,:] A):
    """All sizes implicit in A, returns a tuple of U S V"""

    # start by ensuring we have Fortran style ordering
    cdef double[::1, :] A_f = A.copy_fortran()
    # work out the sizes - it's possible I've got this the wrong way round!
    cdef int m = A.shape[0]
    cdef int n = A.shape[1]

    cdef char jobu[] = 'S'
    cdef char jobvt[] = 'S'

    cdef double[::1,:] U
    cdef double[::1,:] Vt
    cdef double[::1] S

    cdef double[::1] work

    cdef int minnm, maxnm
    cdef int info, lwork, ldu, ldvt

    if m>=n:
       minmn = n
       maxmn = m
    else:
       minmn = m
       maxmn = n

    ldu = m;
    U = np.array((ldu,minmn), order='F')
    ldvt = minmn
    Vt = np.array((ldvt,n), order='F')
    S = np.array((minmn,)) # not absolutely sure  - check this!

    lwork = 5*maxmn
    work = np.array((lwork,))

    dgesvd_(&jobu, &jobvt, &m, &n, &A_f[0,0], &lda, &S[0], &U[0],
           &ldu, &Vt[0,0], &ldvt, &work[0], &lwork, &info);

    return U, S, Vt.T # transpose Vt on the way out
票数 2
EN

Stack Overflow用户

发布于 2015-07-15 06:09:56

您调用dgesdd的方式与its prototype不一致。除此之外,这应该是可行的。例如,请参见this example,它以类似的方式执行来自Cython的dgemm调用。

还要注意的是,Scipy 0.16将包括a Cython API for BLAS/LAPACK,它可能是未来最好的方法。

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

https://stackoverflow.com/questions/31417561

复制
相关文章

相似问题

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