Matrix inversion in Swift using Accelerate Framework - ios

Following the good instructions that I found here: https://github.com/haginile/SwiftAccelerate I verified that matrix inversion works. In fact it did for the example given.
But I get a EXC_BAD_ACCESS error for any other matrix (bigger than 2x2) for example the following 2D matrix (converted as a 1D array) has been tested in matlab and python successfully and it does not work
m = [0.55481645013013, -1.15522603580724, 0.962090414322894, -0.530226035807236, 0.168545207161447, -0.38627124296868, 0.93401699437494, -0.999999999999995, 0.684016994374945, -0.23176274578121, 0.123606797749979, -0.323606797749979, 0.432893622827287, -0.323606797749979, 0.123606797749979, 0.231762745781211, -0.684016994374948, 1.0, -0.934016994374947, 0.386271242968684, 0.168545207161448, -0.530226035807237, 0.962090414322895, -1.15522603580724, 0.554816450130132]
Its inverted matrix should be
inv(AA)
ans =
Columns 1 through 3
-262796763616197 -656991909040516 4.90007819375216
-162417332048282 -406043330120712 14.6405748712708
0.718958226823704 7.87760147961979 30.4010295628018
162417332048287 406043330120730 46.1614842543337
262796763616208 656991909040536 55.9019809318537
Columns 4 through 5
-656991909040528 262796763616211
-406043330120721 162417332048287
-4.28281034550088 -0.718958226823794
406043330120704 -162417332048283
656991909040497 -262796763616196
Could you please give me another way of matrix inversion in Swift? Or explain me how to fix this?
I really don't understand why it does not work.

It doesn't work because the instructions that you found are not so good. Specifically, both pivots and workspace need to be Arrays, not scalar values; it was only working for two-by-two matrices by random chance.
Here's a modified version of the invert function that allocates the workspaces correctly:
func invert(matrix : [Double]) -> [Double] {
var inMatrix = matrix
var N = __CLPK_integer(sqrt(Double(matrix.count)))
var pivots = [__CLPK_integer](count: Int(N), repeatedValue: 0)
var workspace = [Double](count: Int(N), repeatedValue: 0.0)
var error : __CLPK_integer = 0
dgetrf_(&N, &N, &inMatrix, &N, &pivots, &error)
dgetri_(&N, &inMatrix, &N, &pivots, &workspace, &N, &error)
return inMatrix
}
I should also note that your 5x5 matrix is extremely ill-conditioned, so even when you can compute the "inverse" the error of that computation will be very large, and the inverse really shouldn't be used.
A Swift 4 version:
func invert(matrix : [Double]) -> [Double] {
var inMatrix = matrix
var N = __CLPK_integer(sqrt(Double(matrix.count)))
var pivots = [__CLPK_integer](repeating: 0, count: Int(N))
var workspace = [Double](repeating: 0.0, count: Int(N))
var error : __CLPK_integer = 0
withUnsafeMutablePointer(to: &N) {
dgetrf_($0, $0, &inMatrix, $0, &pivots, &error)
dgetri_($0, &inMatrix, $0, &pivots, &workspace, $0, &error)
}
return inMatrix
}

I have written a library for linear algebra in Swift. I call this library swix and it includes functions to invert matrices (this function is called inv).
Example use case:
var b = ones(10)
var A = rand((10, 10))
var AI = inv(A)
var x = AI.dot(b)
Source: https://github.com/stsievert/swix
Documentation: http://scottsievert.com/swix/

Related

Inconsistent results using Metal Performance Shaders between MacBook Pro and iMac

I'm trying to dip my feet into the waters of GPU programming for the first time. I thought I'd start out with something simple and use pre-made kernels (hence the MPS) and just try issuing the commands to the GPU.
My attempt was to simply sum up all values between 1 and 1000. I put each value in a 1x1 matrix and used the MPS Matrix Sum.
On my MacBook Pro, this works as I expect it to.
On my iMac, it gives [0.0] as the result. I figured this was to do with memory, since I use an iGPU on my MacBook Pro and a dGPU on my iMac, however, as far as I can tell, the storageModeShared shouldn't result in this. I even tried adding .synchronize() to the result matrix before trying to read from it, even though I'm pretty sure it shouldn't be necessary with storageModeShared.
The code isn't elegant cause it's just for quickly understanding the workings of issuing commands with MPS and I've tried fixing issues for a little while without keeping track of structure, but it should still be fairly easy to read; If not let me know and I'll refactor it.
The print statements are just to try and debug, aside from print(output)
I hate to paste so much code, but I'm afraid I can't really isolate my issue more.
import Cocoa
import Quartz
import PlaygroundSupport
import MetalPerformanceShaders
let device = MTLCopyAllDevices()[0]
print(MTLCopyAllDevices())
let shaderKernel = MPSMatrixSum.init(device: device, count: 1000, rows: 1, columns: 1, transpose: false)
var matrixList: [MPSMatrix] = []
var GPUStorageBuffers: [MTLBuffer] = []
for i in 1...1000 {
var a = Float32(i)
var b: [Float32] = []
let descriptor = MPSMatrixDescriptor.init(rows: 1, columns: 1, rowBytes: 4, dataType: .float32)
b.append(a)
let buffer = device.makeBuffer(bytes: b, length: 4, options: .storageModeShared)
GPUStorageBuffers.append(buffer!)
let GPUStoredMatrices = MPSMatrix.init(buffer: buffer!, descriptor: descriptor)
matrixList.append(GPUStoredMatrices)
}
let matrices: [MPSMatrix] = matrixList
print(matrices.count)
print("\n")
print(matrices[4].debugDescription)
print("\n")
var printer: [Float32] = []
let pointer2 = matrices[4].data.contents()
let typedPointer2 = pointer2.bindMemory(to: Float32.self, capacity: 1)
let buffpoint2 = UnsafeBufferPointer(start: typedPointer2, count: 1)
buffpoint2.map({value in
printer += [value]
})
print(printer)
let CMDQue = device.makeCommandQueue()
let CMDBuffer = CMDQue!.makeCommandBuffer()
var resultMatrix = MPSMatrix.init(device: device, descriptor: MPSMatrixDescriptor.init(rows: 1, columns: 1, rowBytes: 4, dataType: .float32))
shaderKernel.encode(to: CMDBuffer!, sourceMatrices: matrices, resultMatrix: resultMatrix, scale: nil, offsetVector: nil, biasVector: nil, start: 0)
print(CMDBuffer.debugDescription)
CMDBuffer!.commit()
print(CMDBuffer.debugDescription)
print(CMDQue.debugDescription)
let GPUStartTime = CACurrentMediaTime()
CMDBuffer!.waitUntilCompleted()
var output = [Float32]()
resultMatrix.synchronize(on: CMDBuffer!)
let pointer = resultMatrix.data.contents()
let typedPointer = pointer.bindMemory(to: Float32.self, capacity: 1)
let buffpoint = UnsafeBufferPointer(start: typedPointer, count: 1)
buffpoint.map({value in
output += [value]
})
print(output)
let finish = GPUStartTime - CACurrentMediaTime()
print("\n")
print(finish)

optional chaining in Swift 3: why does one example work and not the other?

Here is a detailed account of a problem following my previous post on Swift optionals.
Thanks to leads given here, here and here, I am able to read fractions (for harmonic ratios) or decimals (for cents) from a string array to calculate the frequencies of notes in musical scales.
Each element in the string array is first tested to see if it contains a / or a . One of two functions then identifies input errors using optional chaining so both fractional and decimal numbers conform to rules outlined in this tuning file format.
Example 1 and 1a shows what happens with correctly entered data in both formats.
Scale with a mixture of fractions and decimals
C D E F G Ab B C’
let tuning = [ "1/1", "193.15686", "5/4", "503.42157", "696.57843", "25/16", "1082.89214", "2/1"]
the column in the debug area shows input data (top down), row shows output frequencies (l-to-r).
Optional("1/1")
Optional("193.15686")
Optional("5/4")
Optional("503.42157")
Optional("696.57843")
Optional("25/16")
Optional("1082.89214")
Optional("2/1")
[261.62599999999998, 292.50676085897425, 327.03249999999997, 349.91970174951047, 391.22212058238728, 408.79062499999998, 489.02764963627084, 523.25199999999995]
Examples 2 & 3 show how both functions react to bad input (i.e. wrongly entered data).
bad fractions are reported (e.g. missing denominator prints a message)
Optional("1/1")
Optional("5/")
User input error - invalid fraction: frequency now being set to 0.0 Hertz
Optional("500.0")
Optional("700.0")
Optional("2/1")
[261.62599999999998, 0.0, 349.22881168708938, 391.99608729493866, 523.25199999999995]
bad decimals are not reported (e.g. after 700 there is no .0 - this should produce a message)
Optional("1/1")
Optional("5/4")
Optional("500.0")
Optional("700")
Optional("2/1")
[261.62599999999998, 327.03249999999997, 349.22881168708938, 0.0, 523.25199999999995]
NOTE: In addition to the report 0.0 (Hz) appears in the row when an optional is nil. This was inserted elsewhere in the code (where it is explained in context with a comment.)
The problem in a nutshell ? the function for fractions reports a fault whereas the function for decimal numbers fails to detect bad input.
Both functions use optional chaining with a guard statement. This works for faulty fractions but nothing I do will make the function report a faulty input condition for decimals. After checking the code thoroughly I’m convinced the problem lies in the conditions I’ve set for the guard statement. But I just can’t get this right. Can anyone please explain what I did wrong ?
Tuner.swift
import UIKit
class Tuner {
var tuning = [String]()
let tonic: Double = 261.626 // frequency of middle C
var index = -1
let centsPerOctave: Double = 1200.0 // mandated by Scala tuning file format
let formalOctave: Double = 2.0 // Double for stretched-octave tunings
init(tuning: [String]) {
self.tuning = tuning
let frequency = tuning.flatMap(doubleFromDecimalOrFraction)
print(frequency)
}
func doubleFromDecimalOrFraction(s: String?) -> Double {
index += 1
let whichNumericStringType = s
print(whichNumericStringType as Any) // eavesdrop on String?
var possibleFrequency: Double?
// first process decimal.
if (whichNumericStringType?.contains("."))! {
possibleFrequency = processDecimal(s: s)
}
// then process fractional.
if (whichNumericStringType?.contains("/"))! {
possibleFrequency = processFractional(s: s)
}
// Insert "0.0" marker. Remove when processDecimal works
let noteFrequency = possibleFrequency
let zeroFrequency = 0.0
// when noteFrequency? is nil, possibleFrequency is set to zeroFrequency
let frequency = noteFrequency ?? zeroFrequency
return frequency // TO DO let note: (index: Int, frequency: Double)
}
func processFractional(s: String?) -> Double? {
var fractionArray = s?.components(separatedBy: "/")
guard let numerator = Double((fractionArray?[0])!.digits),
let denominator = Double((fractionArray?[1])!.digits),
numerator > 0,
denominator != 0,
fractionArray?.count == 2
else
{
let possibleFrequency = 0.0
print("User input error - invalid fraction: frequency now being set to \(possibleFrequency) Hertz ")
return possibleFrequency
}
let possibleFrequency = tonic * (numerator / denominator)
return possibleFrequency
}
func processDecimal(s: String?) -> Double? {
let decimalArray = s?.components(separatedBy: ".")
guard let _ = s,
decimalArray?.count == 2
else
{
let denominator = 1
let possibleFrequency = 0.0
print("User input error (value read as \(s!.digits)/\(denominator) - see SCL format, http://www.huygens-fokker.org/scala/scl_format.html): frequency now being forced to \(possibleFrequency) Hertz ")
return possibleFrequency
}
let power = Double(s!)!/centsPerOctave
let possibleFrequency = tonic * (formalOctave**power)
return possibleFrequency
}
}
extension String {
var digits: String {
return components(separatedBy: CharacterSet.decimalDigits.inverted).joined()
}
}
precedencegroup Exponentiative {
associativity: left
higherThan: MultiplicationPrecedence
}
infix operator ** : Exponentiative
func ** (num: Double, power: Double) -> Double{
return pow(num, power)
}
ViewController.swift
import UIKit
class ViewController: UIViewController {
// test pitches: rational fractions and decimal numbers (currently 'good')
let tuning = ["1/1", "5/4", "500.0", "700.0", "2/1"]
// Diatonic scale: rational fractions
// let tuning = [ "1/1", "9/8", "5/4", "4/3", "3/2", "27/16", "15/8", "2/1"]
// Mohajira: rational fractions
// let tuning = [ "21/20", "9/8", "6/5", "49/40", "4/3", "7/5", "3/2", "8/5", "49/30", "9/5", "11/6", "2/1"]
// Diatonic scale: 12-tET
// let tuning = [ "0.0", "200.0", "400.0", "500", "700.0", "900.0", "1100.0", "1200.0"]
// Diatonic scale: mixed 12-tET and rational fractions
// let tuning = [ "0.0", "9/8", "400.0", "4/3", "700.0", "27/16", "1100.0", "2/1"]
// Diatonic scale: 19-tET
// let tuning = [ "0.0", "189.48", "315.8", "505.28", "694.76", "884.24", "1073.72", "1200.0"]
// Diatonic 1/4-comma meantone scale. Pietro Aaron's temperament (1523) : mixed cents and rational fractions
// let tuning = [ "1/1", "193.15686", "5/4", "503.42157", "696.57843", "25/16", "1082.89214", "2/1"]
override func viewDidLoad() {
super.viewDidLoad()
_ = Tuner(tuning: tuning)
}
}
The problem in a nutshell ? the function for fractions reports a fault whereas the function for decimal numbers fails to detect bad input.
The function for decimal numbers does detect “bad” input. However, "700" does not contain ".", and you only call processDecimal(s:) if the string does contain ".". If the string doesn't contain "." and also doesn't contain "/", doubleFromDecimalOrFraction(s:) doesn't call any function to parse the string.

How to make a closure in Swift extract two integers from a string to perform a calculation

I am currently using map property with a closure in Swift to extract linear factors from an array and calculate a list of musical frequencies spanning one octave.
let tonic: Double = 261.626 // middle C
let factors = [ 1.0, 1.125, 1.25, 1.333, 1.5, 1.625, 1.875]
let frequencies = factors.map { $0 * tonic }
print(frequencies)
// [261.62599999999998, 294.32925, 327.03249999999997, 348.74745799999994, 392.43899999999996, 425.14224999999999, 490.54874999999993]
I want to do this by making the closure extract two integers from a string and divide them to form each factor. The string comes from an SCL tuning file and might look something like this:
// C D E F G A B
let ratios = [ "1/1", "9/8", "5/4", "4/3", "3/2", "27/16", "15/8"]
Can this be done ?
SOLUTION
Thankfully, yes it can. In three Swift statements tuning ratios represented as fractions since before Ptolemy can be coverted into precise frequencies. A slight modification to the accepted answer makes it possible to derive the list of frequencies. Here is the code
import UIKit
class ViewController: UIViewController {
// Diatonic scale
let ratios = [ "1/1", "9/8", "5/4", "4/3", "3/2", "27/16", "15/8"]
// Mohajira scale
// let ratios = [ "21/20", "9/8", "6/5", "49/40", "4/3", "7/5", "3/2", "8/5", "49/30", "9/5", "11/6", "2/1"]
override func viewDidLoad() {
super.viewDidLoad()
_ = Tuning(ratios: ratios)
}
}
Tuning Class
import UIKit
class Tuning {
let tonic = 261.626 // frequency of middle C (in Hertz)
var ratios = [String]()
init(ratios: [String]) {
self.ratios = ratios
let frequencies = ratios.map { s -> Double in
let integers = s.characters.split(separator: "/").map(String.init).map({ Double($0) })
return (integers[0]!/integers[1]!) * tonic
}
print("// \(frequencies)")
}
}
And here is the list of frequencies in Hertz corresponding to notes of the diatonic scale
C D E F G A B
[261.626007, 294.329254, 327.032501, 348.834686, 392.439026, 441.493896, 490.548767]
It works for other scales with pitches not usually found on a black-and-white-note music keyboard
Mohajira scale created by Jacques Dudon
// D F G C'
let ratios = [ "21/20", "9/8", "6/5", "49/40", "4/3", "7/5", "3/2", "8/5", "49/30", "9/5", "11/6", "2/1"]
And here is a list of frequencies produced
// D F G C'
// [274.70729999999998, 294.32925, 313.95119999999997, 320.49185, 348.83466666666664, 366.27639999999997, 392.43899999999996, 418.60159999999996, 427.32246666666663, 470.92679999999996, 479.64766666666662, 523.25199999999995]
Disclaimer
Currently the closure only handles rational scales. To fully comply with Scala SCL format it must also be able to distinguish between strings with fractions and strings with a decimal point and interpret the latter using cents, i.e. logarithmic rather than linear factors.
Thank you KangKang Adrian and Atem
let ratios = [ "1/1", "9/8", "5/4", "4/3", "3/2", "27/16", "15/8"]
let factors = ratios.map { s -> Float in
let integers = s.characters.split(separator: "/").map(String.init).map({ Float($0) })
return integers[0]!/integers[1]!
}
If I understand your question, you can do something like that:
func linearFactors(from string: String) -> Double? {
let components = string.components(separatedBy: "/").flatMap { Double($0) }
if let numerator = components.first, let denominator = components.last {
return numerator / denominator
}
return nil
}
Convert ratios to array of double
let ratios = [ "1/1", "9/8", "5/4", "4/3", "3/2", "27/16", "15/8"]
let array = ratios.flatMap { element in
let parts = element.components(separatedBy: "/")
guard parts.count == 2,
let dividend = Double(parts[0]),
let divisor = Double(parts[1]),
divisor != 0
else {
return nil
}
return parts[0] / parts[1]
}

FFT Calculating incorrectly - Swift

I am trying to take the fast Fast Fourier Transform. I am basing my calculation off of the Surge. I am having trouble getting correct results. When I take the fft of a 1000 hz sound I get something that looks like this. . When i take the same tone and use python I get something that looks way more correct. The python code looks like:
import numpy as np
import scipy.io.wavfile
import numpy.fft
import matplotlib.pyplot as plt
FILENAME = 'beep.wav'
fs, data = scipy.io.wavfile.read(FILENAME)
data = data[:801]
spacing = 1 / float(fs)
freq = numpy.fft.rfft(data)
freq_power = np.abs(freq)
a = 1 / (2 * spacing)
b = (len(data) + 1) // 2
freq_axis = np.linspace(0, a, b)
plt.plot(freq_axis, freq_power)
plt.show()
The swift code looks like
import Accelerate
public func sqrt(x: [Float]) -> [Float] {
var results = [Float](count: x.count, repeatedValue: 0.0)
vvsqrtf(&results, x, [Int32(x.count)])
return results
}
public func fft(input: [Float]) -> [Float] {
var real = [Float](input)
var imaginary = [Float](count: input.count, repeatedValue: 0.0)
var splitComplex = DSPSplitComplex(realp: &real, imagp: &imaginary)
let length = vDSP_Length(floor(log2(Float(input.count))))
let radix = FFTRadix(kFFTRadix2)
let weights = vDSP_create_fftsetup(length, radix)
println(weights)
vDSP_fft_zip(weights, &splitComplex, 1, 8, FFTDirection(FFT_FORWARD))
var magnitudes = [Float](count: input.count, repeatedValue: 0.0)
vDSP_zvmags(&splitComplex, 1, &magnitudes, 1, vDSP_Length(input.count))
var normalizedMagnitudes = [Float](count: input.count, repeatedValue: 0.0)
vDSP_vsmul(sqrt(magnitudes), 1, [2.0 / Float(input.count)], &normalizedMagnitudes, 1, vDSP_Length(input.count))
vDSP_destroy_fftsetup(weights)
return normalizedMagnitudes
}
To reiterate. The swift code is the code giving unexpected results. What am I doing wrong?
It looks like you are using Swift Float arrays with the Accelerate framework, but you might instead need to allocate your vectors using UnsafeMutablePointer<Float> types since the Accelerate framework is an Objective C framework. Here is an example how to do this.
public func sqrt(x: [Float]) -> [Float] {
// convert swift array to C vector
var temp = UnsafeMutablePointer<Float>.alloc(x.count)
for (var i=0;i<x.count;i++) {
temp[i] = x[i];
}
var count = UnsafeMutablePointer<Int32>.alloc(1)
count[0] = Int32(x.count)
vvsqrtf(temp, temp, count)
// convert C vector to swift array
var results = [Float](count: x.count, repeatedValue: 0.0)
for (var i=0;i<x.count;i++) {
results[i] = temp[i];
}
// Free memory
count.dealloc(1)
temp.dealloc(x.count)
return results
}
It will work out better for performance to use the UnsafeMutablePointer<Float> types throughout your code for your vectors of data rather than converting back and forth in function calls as I did for this example. Also you should save your FFT setup and reuse that as well for better performance.
Since you're using the vDSP FFT you might also like the vDSP_zvabs API which calculates magnitude in dB from the FFT results.
Finally be sure to read this link on data packing and scaling for the Accelerate framework FFT APIs.
https://developer.apple.com/library/mac/documentation/Performance/Conceptual/vDSP_Programming_Guide/UsingFourierTransforms/UsingFourierTransforms.html
To improve performance, the vDSP APIs do not output the most obvious scale values (since you will undoubtedly be scaling the data anyway somewhere else) and they pack in some extra data into a few of the FFT points.

sum of results from for - in loop, in swift

I am playing around with Apples sample code for Health kit. They have put a for-in loop function to iterate through all the sample within the last 24hours. The code of course works great.
Using the for-in loop in swift, would it be possible to find the sum of all the values?
I have been trying but can not find the solution.
Thanks
Chris
Here is the code:
for sample in results as [HKQuantitySample] {
let joules = sample.quantity.doubleValueForUnit(HKUnit.jouleUnit())
I'm not familiar with the Health Kit framework, but you can sum all of the values in an array using reduce:
let array = [1, 2, 3, 4, 5]
let sum = array.reduce(0, +) // sum == 15
0 is the starting value, and + is the operation to be performed on the starting value and each item in the array.
Looking at your code, you might need to provide a closure to reduce, something like this:
let samples = results as [HKQuantitySample]
let sum = samples.reduce(0.0) {
$0 + $1.quantity.doubleValueForUnit(HKUnit.jouleUnit())
}
Assuming samples is an HKQuantitySample array :
// samples is an [HKQuantitySample]
var joulesSum : Double = 0.0 // Make sure that : it's a var not a let and Double is the right type
for aSample in samples {
joulesSum += aSample.quantity.doubleValueForUnit(HKUnit.jouleUnit())
}
Or in your case :
var joulesSum : Double = 0.0
for aResult in results {
joulesSum += aResult.quantity.doubleValueForUnit(HKUnit.jouleUnit())
}
Did it helped ? If it didn't, please add the previous code (where your results is created).

Resources