Matrix multiplication and inverse problems with acceleration

I am trying to multiply two matrices in Objective-C. I imported the acceleration view into my project in Xcode, everything compiles just fine. I did the matrix multiplication by my calculator and got the correct values, however when I run the code I do not. This is how I defined my matrices.

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

Then I used the mmul function in acceleration view.

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

The results of the array were created by doing the following.

 float results[3][1]; 

I just put this in the viewDidLoad method for an empty project so that I can NSLog get the results. Therefore, when I multiply matrix A by matrix B, I should get the following results .. (-1, 10, -3). However, the results in NSLog show (-0.045, 0,000, 0,000). This is not true, and I do not understand why. I realized that this function will multiply two matrices together. But I'm not sure what he is doing. I probably entered something wrong and hoped that someone could help me.

Side note: matrixA is indeed an inverse of another matrix. However, I can not find anything in terms of acceleration, which will take the opposite. I found a function called

 sgetrf_ 

with LAPACK, but actually it doesnโ€™t work. If anyone has any help, advice or some kind of textbook, I will be grateful for this, Iโ€™ve been watching things on the Internet for three days now!

+6
source share
2 answers

You pass pointers to memory after the end of your matrices.

The commit will look like this (unverified code):

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

Passing the array to a function in C will actually pass a pointer to the first element of the array, which in this case will be what you need to do. You passed a pointer to a piece of memory immediately after the last element of the array in your matrices, which means that you will get meaningless results or a failure.

+6
source

Skip three different ways to do this calculation (including the opposite) on OS X or iOS.

First, let's do what you more or less tried to do for starters: we will do the calculation using LAPACK and BLAS from the Accelerate view. Note that I used the BLAS function cblas_sgemv instead of vDSP_mmul to multiply the matrix vector. I did this for three reasons. Firstly, it is more idiomatic in code that uses LAPACK. Secondly, LAPACK really wants the matrices to be stored in the main column, which supports BLAS, but vDSP does not. Finally, vDSP_mmul is actually just a wrapper around BLAS matrix multiplications, so we can cut out the middleman. This will work on OS X up to 10.2 and iOS up to 4.0 - i.e. for any purpose you can count on today.

 #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 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]); } 

Then we will do the calculation using LinearAlgebra.h, which is a new feature of the accelerator system in iOS 8.0 and OS X 10.10. It abstracts almost all the accounting information needed for these calculations, but it offers only a tiny piece of full functionality, available in LAPACK and BLAS. Note that while there is some scheme needed to convert our raw arrays to and from la_objects, as soon as we have them, the actual calculation is very simple.

 #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 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]); } 

And finally, another method. If your matrices are really only 3x3, this is the method I would use, because the overhead associated with any of the previous methods will swamp the actual calculation. However, this only works for matrices 4x4 or smaller. Another new title in iOS 8.0 and OS X 10.10 is specifically focused on small matrix and vector maths, which makes this very simple and effective:

 #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]); } 

And finally, letโ€™s just double check that they all give the same results (up to small rounding differences):

 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 ] 
+21
source

Source: https://habr.com/ru/post/984070/


All Articles