繁体   English   中英

矩阵乘法和逆问题与加速框架

[英]Matrix multiplication and inverse problems with accelerate framework

我试图在Objective-C中乘以两个矩阵。 我已经将加速框架导入了我在Xcode中的项目,一切都编译得很好。 我在我的计算器上进行了矩阵乘法并得到了正确的值,但是,在运行代码时,我没有。 这就是我定义矩阵的方式..

float matrixA [3][3] = {{-.045, -.141, -.079}, {-.012, -.079, .0578}, {.112, -.011, -.0830}};

float matrixB [3][1] = {{40}, {-61}, {98}};

然后我在加速框架中使用了mmul函数。

vDSP_mmul(&matrixA[3][3], 1, &matrixB[3][1], 1, &results[3][1], 1, 3, 1, 3);

通过执行以下操作创建了数组结果。

float results[3][1];

我只是把它放在一个空项目的viewDidLoad方法中,所以我可以NSLog结果。 所以当我将matrixA乘以matrixB时,我得到以下结果..(-1,10,-3)。 但是,NSLog中的结果显示(-0.045,0.000,0.000)。 这是不正确的,我不明白为什么。 我的理解是这个函数会将两个矩阵相乘。 但我不确定它在做什么。 我可能输错了东西,并希望有人可以帮助我。

侧注:matrixA实际上是另一个矩阵的逆。 但是,我在加速框架中找不到任何反向的东西。 我确实找到了一个叫做的函数

sgetrf_

有了LAPACK但是没有真正得到它。 如果有人有任何帮助,建议或一些教程可以遵循我会很感激,已经在这三天了,现在在互联网上寻找东西!

让我们通过三种不同的方式在OS X或iOS上进行这种计算(包括逆向)。

首先,让我们做你或多或少尝试做的事情:我们将使用Accelerate框架中的LAPACK和BLAS进行计算。 请注意,我使用BLAS函数cblas_sgemv而不是vDSP_mmul来执行矩阵向量乘法。 我这样做有三个原因。 首先,它在使用LAPACK的代码中更具惯用性。 其次,LAPACK确实希望以列主要顺序存储矩阵,BLAS支持这些矩阵,但vDSP不支持。 最后, vDSP_mmul实际上只是BLAS矩阵乘法例程的包装器,因此我们可以删除中间人。 这将在OS X上恢复到10.2并且iOS可以恢复到4.0 - 即在您今天可以合理期望遇到的任何目标上。

#include <Accelerate/Accelerate.h>
#include <stdio.h>
#include <string.h>

void using_blas_and_lapack(void) {
    printf("Using BLAS and LAPACK:\n");
    //  Note: you'll want to store A in *column-major* order to use it with
    //  LAPACK (even though it's not strictly necessary for this simple example,
    //  if you try to do something more complex you'll need it).
    float A[3][3] = {{-4,-3,-5}, {6,-7, 9}, {8,-2,-1}};
    float x[3] = { -1, 10, -3};
    //  Compute b = Ax using cblas_sgemv.
    float b[3];
    cblas_sgemv(CblasColMajor, CblasNoTrans, 3, 3, 1.f, &A[0][0], 3, x, 1, 0.f, b, 1);
    printf("b := A x = [ %g, %g, %g ]\n", b[0], b[1], b[2]);
    //  You probably don't actually want to compute A^-1; instead you simply
    //  want to solve the equation Ay = b for y (like y = A\b in matlab).  To
    //  do this with LAPACK, you typically use the routines sgetrf and sgetrs.
    //  sgetrf will overwrite its input matrix with the LU factorization, so
    //  we'll make a copy first in case you need to use A again.
    float factored[3][3];
    memcpy(factored, A, sizeof factored);
    //  Now that we have our copy, go ahead and factor it using sgetrf.
    __CLPK_integer n = 3;
    __CLPK_integer info = 0;
    __CLPK_integer ipiv[3];
    sgetrf_(&n, &n, &factored[0][0], &n, ipiv, &info);
    if (info != 0) { printf("Something went wrong factoring A\n"); return; }
    //  Finally, use the factored matrix to solve y = A\b via sgetrs.  Just
    //  like sgetrf overwrites the matrix with its factored form, sgetrs
    //  overwrites the input vector with the solution, so we'll make a copy
    //  before calling the function.
    float y[3];
    memcpy(y, b, sizeof y);
    __CLPK_integer nrhs = 1;
    sgetrs_("No transpose", &n, &nrhs, &factored[0][0], &n, ipiv, y, &n, &info);
    printf("y := A\\b = [ %g, %g, %g ]\n\n", y[0], y[1], y[2]);
}

接下来,让我们使用LinearAlgebra.h进行计算,这是iOS 8.0和OS X 10.10中Accelerate Framework的一个新功能。 它抽象了几乎所有这些计算所需的簿记,但它只提供了LAPACK和BLAS中可用的全部功能的一小部分。 请注意,虽然有一些样板需要将原始数组转换为la_objects和从la_objects转换,但是一旦我们得到它们,实际的计算就非常简单了。

#include <Accelerate/Accelerate.h>
#include <stdio.h>

void using_la(void) {
    printf("Using LA:\n");
    //  LA accepts row-major as well as column-major data, but requires a short
    //  two-step dance to get our data in.
    float Adata[3][3] = {{-4, 6, 8}, {-3,-7,-2}, {-5, 9,-1}};
    float xdata[3] = { -1, 10, -3};
    la_object_t A = la_matrix_from_float_buffer(&Adata[0][0], 3, 3, 3, LA_NO_HINT, LA_DEFAULT_ATTRIBUTES);
    la_object_t x = la_vector_from_float_buffer(xdata, 3, 1, LA_DEFAULT_ATTRIBUTES);
    //  Once our data is stored as LA objects, it's easy to do the computation:
    la_object_t b = la_matrix_product(A, x);
    la_object_t y = la_solve(A, b);
    //  And finally we need to get our data back out:
    float bdata[3];
    if (la_vector_to_float_buffer(bdata, 1, b) != LA_SUCCESS) {
        printf("Something went wrong computing b.\n");
        return;
    } else printf("b := A x = [ %g, %g, %g ]\n", bdata[0], bdata[1], bdata[2]);
    float ydata[3];
    if (la_vector_to_float_buffer(ydata, 1, y) != LA_SUCCESS) {
        printf("Something went wrong computing y.\n");
        return;
    } else printf("y := A\\b = [ %g, %g, %g ]\n\n", ydata[0], ydata[1], ydata[2]);
}

最后,还有一种方法。 如果你的矩阵实际上只是3x3,这就是我将使用的方法,因为前面任一方法所涉及的开销都会影响实际的计算。 但是,这仅适用于尺寸为4x4或更小的矩阵。 在iOS 8.0和OS X 10.10中还有另一个新的标题,专门针对小矩阵和矢量数学,这使得这非常简单和有效:

#include <simd/simd.h>
#include <stdio.h>

void using_simd(void) {
    printf("Using <simd/simd.h>:\n");
    matrix_float3x3 A = matrix_from_rows((vector_float3){-4,  6,  8},
                                         (vector_float3){-3, -7, -2},
                                         (vector_float3){-5,  9, -1});
    vector_float3 x = { -1, 10, -3 };
    vector_float3 b = matrix_multiply(A, x);
    printf("b := A x = [ %g, %g, %g ]\n", b[0], b[1], b[2]);
    vector_float3 y = matrix_multiply(matrix_invert(A),b);
    printf("y := A^-1 b = [ %g, %g, %g ]\n\n", y[0], y[1], y[2]);
}

最后,让我们仔细检查这些都会得到相同的结果(直到小的舍入差异):

scanon$ xcrun -sdk macosx clang matrix.m -framework Accelerate  && ./a.out
Using BLAS and LAPACK:
b := A x = [ 40, -61, 98 ]
y := A\b = [ -0.999999, 10, -3 ]

Using LA:
b := A x = [ 40, -61, 98 ]
y := A\b = [ -1, 10, -3 ]

Using <simd/simd.h>:
b := A x = [ 40, -61, 98 ]
y := A^-1 b = [ -1, 10, -3 ]

在矩阵结束后 ,您将指针传递给内存。

修复看起来像这样(未经测试的代码):

vDSP_mmul(&matrixA[0][0], 1, &matrixB[0][0], 1, &results[0][0], 1, 3, 1, 3);

将数组传递给C中的函数实际上会将指针传递给数组的第一个元素,在这种情况下,这似乎是您需要做的事情。 你在矩阵中的最后一个数组元素之后直接传递指向一块内存的指针,这意味着你会得到无意义的结果或崩溃。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM