Solving Linear Equations with Swift and Accelerate

In this post we’ll cover solving a system of linear equations using Swift and Accelerate. It get’s a little bit hairy, but it’s not so bad once you get the hang of it.

We’ll need to perform an LU factorization as before. Then we’ll solve the system of linear equations using the dgetrs_() function from the Accelerate framework, along with the documentation at netlib.org.

To make matters interesting, the first argument of the dgetrs_() function is a letter telling the function whether your matrix should be interpreted as column-major, as in Fortran, or whether it should be interpreted as row-major, as in C and every other language. If you want column major, use “N”, otherwise for row-major, use “T”. This gets interesting because the C code expects a UInt8 pointer or something, and a Swift string just isn’t going to cut it. To make C and Swift play nicely, we had to do some weird stuff on line 20 that I’m not wholly comfortable with yet, but it worked.

import Accelerate

func solve( A:[Double], _ B:[Double] ) -> [Double] {
    var inMatrix:[Double]       = A
    var solution:[Double]       = B
    // Get the dimensions of the matrix. An NxN matrix has N^2
    // elements, so sqrt( N^2 ) will return N, the dimension
    var N:__CLPK_integer        = __CLPK_integer( sqrt( Double( A.count ) ) )
    // Number of columns on the RHS
    var NRHS:__CLPK_integer     = 1
    // Leading dimension of A and B
    var LDA:__CLPK_integer      = N
    var LDB:__CLPK_integer      = N
    // Initialize some arrays for the dgetrf_(), and dgetri_() functions
    var pivots:[__CLPK_integer] = [__CLPK_integer](count: Int(N), repeatedValue: 0)
    var error: __CLPK_integer   = 0
    // Perform LU factorization
    dgetrf_(&N, &N, &inMatrix, &N, &pivots, &error)
    // Calculate solution from LU factorization
    _ = "T".withCString {
        dgetrs_( UnsafeMutablePointer($0), &N, &NRHS, &inMatrix, &LDA, &pivots, &solution, &LDB, &error )
    }
    return solution
}


var A: [Double] = [ 1, 1, 4, 6 ]
var B: [Double] = [ 383, 2034 ]

var soln = solve( A, B )

print( soln ) // --> [ 132.0, 251.0 ]

References:

Using Legacy C APIs with Swift

UnsafeMutablePointer from String in Swift