使用 LAPACK 访问子矩阵

发布于 2024-10-17 23:19:14 字数 69 浏览 3 评论 0原文

LAPACK 中有一个函数可以给我特定子矩阵的元素吗?如果是的话,C++ 的语法是什么?

或者我需要编码吗?

Is there a function in LAPACK, which will give me the elements of a particular submatrix? If so how what is the syntax in C++?

Or do I need to code it up?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

梦里°也失望 2024-10-24 23:19:14

没有用于访问子矩阵的函数。然而,由于 LAPACK 例程中矩阵数据的存储方式,您不需要这样的例程。这节省了大量的复制工作,并且(部分)选择了数据布局,原因如下:

回想一下,LAPACK 中的密集(即非带状、三角形、厄米特等)矩阵由四个值定义:

  • 指向顶部的指针矩阵的左角 矩阵的
  • 行数 矩阵的
  • 列数 矩阵
  • 的“前导维度”;通常,这是内存中一行相邻元素之间的距离。

大多数时候,大多数人只使用等于行数的前导维度; 3x3 矩阵通常像这样存储:

a[0] a[3] a[6] 
a[1] a[4] a[7]
a[2] a[5] a[8]

假设我们想要一个具有前导维度 lda 的巨大矩阵的 3x3 子矩阵。假设我们特别想要左上角位于 a(15,42) 的 3x3 子矩阵:

         .             .            .
         .             .            .
... a[15+42*lda] a[15+43*lda] a[15+44*lda] ...
... a[16+42*lda] a[16+43*lda] a[16+44*lda] ...
... a[17+42*lda] a[17+43*lda] a[17+44*lda] ...
         .             .            .
         .             .            .

我们可以将此 3x3 矩阵复制到连续存储中,但如果我们想将其作为输入传递(或输出)矩阵到 LAPACK 例程,我们不需要;我们只需要适当地定义参数即可。我们称这个子矩阵为b;然后我们定义:

// pointer to the top-left corner of b:
float *b = &a[15 + 42*lda];
// number of rows in b:
const int nb = 3;
// number of columns in b:
const int mb = 3;
// leading dimension of b:
const int ldb = lda;

唯一可能令人惊讶的是ldb的值;通过使用“大矩阵”的值lda,我们可以在不复制的情况下寻址子矩阵,并就地对其进行操作。

但是
我撒了谎(某种程度上)。有时您确实无法就地操作子矩阵,并且确实需要复制它。我不想谈论这一点,因为这种情况很少见,并且您应该尽可能使用就地操作,但如果不告诉您这是可能的,我会感到很难过。例程:

SLACPY(UPLO,M,N,A,LDA,B,LDB)

复制左上角为AMxN矩阵,并以前导维度LDA 到左上角为 B 并具有前导维度 LDBMxN 矩阵。 UPLO 参数指示是复制上三角形、下三角形还是整个矩阵。

在我上面给出的示例中,您可以像这样使用它(假设使用 clapack 绑定):

...
const int m = 3;
const int n = 3;
float b[9];
const int ldb = 3;
slacpy("A",  // anything except "U" or "L" means "copy everything"
       &m,   // number of rows to copy
       &n,   // number of columns to copy
       &a[15 + 42*lda], // pointer to top-left element to copy
       lda,  // leading dimension of a (something huge)
       b,    // pointer to top-left element of destination
       ldb); // leading dimension of b (== m, so storage is dense)
...

There is no function for accessing a submatrix. However, because of the way matrix data is stored in LAPACK routines, you don't need one. This saves a lot of copying, and the data layout was (partially) chosen for this reason:

Recall that a dense (i.e., not banded, triangular, hermitian, etc) matrix in LAPACK is defined by four values:

  • a pointer to the top left corner of the matrix
  • the number of rows in the matrix
  • the number of columns in the matrix
  • the "leading dimension" of the matrix; typically this is the distance in memory between adjacent elements of a row.

Most of the time, most people only ever use a leading dimension that is equal to the number of rows; a 3x3 matrix is typically stored like so:

a[0] a[3] a[6] 
a[1] a[4] a[7]
a[2] a[5] a[8]

Suppose instead that we wanted a 3x3 submatrix of a huge matrix with leading dimension lda. Suppose we specifically want the 3x3 submatrix whose top-left corner is located at a(15,42):

         .             .            .
         .             .            .
... a[15+42*lda] a[15+43*lda] a[15+44*lda] ...
... a[16+42*lda] a[16+43*lda] a[16+44*lda] ...
... a[17+42*lda] a[17+43*lda] a[17+44*lda] ...
         .             .            .
         .             .            .

We could copy this 3x3 matrix into contiguous storage, but if we want to pass it as an input (or output) matrix to an LAPACK routine, we don't need to; we only need to define the parameters appropriately. Let's call this submatrix b; we then define:

// pointer to the top-left corner of b:
float *b = &a[15 + 42*lda];
// number of rows in b:
const int nb = 3;
// number of columns in b:
const int mb = 3;
// leading dimension of b:
const int ldb = lda;

The only thing that might be surprising is the value of ldb; by using the value lda of the "big matrix", we can address the submatrix without copying, and operate on it in-place.

However
I lied (sort of). Sometimes you really can't operate on a submatrix in place, and genuinely need to copy it. I didn't want to talk about that, because it's rare, and you should use in-place operations whenever possible, but I would feel bad not telling you that it is possible. The routine:

SLACPY(UPLO,M,N,A,LDA,B,LDB)

copies the MxN matrix whose top-left corner is A and is stored with leading dimension LDA to the MxN matrix whose top-left corner is B and has leading dimension LDB. The UPLO parameter indicates whether to copy the upper triangle, lower triangle, or the whole matrix.

In the example I gave above, you would use it like this (assuming the clapack bindings):

...
const int m = 3;
const int n = 3;
float b[9];
const int ldb = 3;
slacpy("A",  // anything except "U" or "L" means "copy everything"
       &m,   // number of rows to copy
       &n,   // number of columns to copy
       &a[15 + 42*lda], // pointer to top-left element to copy
       lda,  // leading dimension of a (something huge)
       b,    // pointer to top-left element of destination
       ldb); // leading dimension of b (== m, so storage is dense)
...
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文