Is there a way to override the Copy on Write behavior for Swift arrays? - swift

I'm working on a project where I need to work with large arrays, and by using UnsafeMutablePointers, I get a threefold speed increase over using the regular array methods. However, I believe the copy on write behavior is causing me to change instances that I do not want to be affected. For example, in the following code, I want to update the values in copyArray, but leave the original values in anArray.
import Foundation
func increaseWithPointers(_ arr: inout [Int]) {
let count = arr.count
let ptr = UnsafeMutablePointer(mutating: &arr)
for i in 0..<count {
ptr[i] = ptr[i] + 1
}
}
var anArray = [1,2,3,4,5]
var copyArray = anArray
increaseWithPointers(&copyArray)
print(anArray)
Executing this code prints [2,3,4,5,6].
I can get around this by declaring copyArray as follows:
var copyArray = [Int](repeating: 0, count: 5)
for i in 0..<5 {
copyArray[i] = anArray[i]
}
However, this requires writing each value twice: to zero, then to the intended value. Is there a way to efficiently guarantee a copy of an array?

I can reproduce your problem using Xcode 9 beta 3, but not using Xcode 8.3.3. I suggest you file a Swift bug report.
This fixes the problem:
import Foundation
func increaseWithPointers(_ arr: inout [Int]) {
arr.withUnsafeMutableBufferPointer { (buffer) in
for i in buffer.indices {
buffer[i] += 1
}
}
}
var anArray = [1,2,3,4,5]
var copyArray = anArray
increaseWithPointers(&copyArray)
print(anArray)

Related

Class variables are deallocated after calling function

I have a function in swift, as below. There is a loop with a reference to variables existing within an instance of this class. (fftfilterbankReal is an array in the class). However after one pass, I get an error with 'index out of range' at the code line 'for i in 0..
In the debugger it seems that on the 2nd iteration of this loop, there are no variables under the 'self' drop down.
If I comment out the line 'vDSP_zvmul(&kernel!, 1, &fft1Input, 1, &result, 1, vDSP_Length(r.count), 1)' then the loop runs and I can debug at any time and visually see the self variables in the debugger.
What am I missing that seems to make these variables disappear? I have read into memory allocation and such, and my class variables are declared using 'var' and nothing more, as that should default to strong in swift.
func convolveInput(realsamples:[Float], imagsamples:[Float]) -> [Float]{
realResult = Array(repeating: [], count: filterbankReal.count)
imagResult = Array(repeating: [], count: filterbankReal.count)
let x = realsamples
let y = imagsamples
var N = x.count
var logN = 16
var fft1Setup = vDSP_create_fftsetup(UInt(logN), FFTRadix(FFT_RADIX2))!
var paddedLength = x.count + filterbankReal.count - 1
var halfPaddedLength = paddedLength/2
var halfKernelLength = kernelLength/2
//setup Complex Buffer 1
var reals = [Float]()
var imags = [Float]()
for i in 0..<x.count{
reals.append(x[i])
imags.append(y[i])
}
var complexBuffer1 = DSPSplitComplex(realp: UnsafeMutablePointer(mutating: reals), imagp: UnsafeMutablePointer(mutating: imags))
//Perform FFT on incoming samples
var re = [Float](repeating:0.0, count: N)
var im = [Float](repeating:0.0, count: N)
var fft1Input = DSPSplitComplex(realp: UnsafeMutablePointer(mutating: re), imagp: UnsafeMutablePointer(mutating: im))
var fftlength = 10
vDSP_fft_zop(fft1Setup, &(complexBuffer1), 1, &fft1Input, 1, UInt(fftlength), Int32(FFT_FORWARD))
//Remove DC from FFT Signal
re.remove(at: 0)
im.remove(at: 0)
for i in 0..<self.fftfilterbankReal.count {
var r:[Float] = self.fftfilterbankReal[i]
var im:[Float] = self.fftfilterbankImag[i]
var kernel:DSPSplitComplex? = DSPSplitComplex(realp: &r, imagp: &im)
var res:Float = 0
var ims:Float = 0
var result:DSPSplitComplex = DSPSplitComplex(realp: &res, imagp: &ims)
vDSP_zvmul(&kernel!, 1, &fft1Input, 1, &result, 1, vDSP_Length(r.count), 1)
self.realResult[i].append(res)
self.imagResult[i].append(ims)
}
Your code is sort of a showcase of bad usages when working with Arrays and pointers.
For example:
var complexBuffer1 = DSPSplitComplex(realp: UnsafeMutablePointer(mutating: reals), imagp: UnsafeMutablePointer(mutating: imags))
or:
var kernel:DSPSplitComplex? = DSPSplitComplex(realp: &r, imagp: &im)
DSPSplitComplex holds two pointers for real part and imaginary part separately and does not copy the contents. You should not pass Swift Arrays for such parameters.
And the most critical part in your code is...
var res:Float = 0
var ims:Float = 0
var result:DSPSplitComplex = DSPSplitComplex(realp: &res, imagp: &ims)
vDSP_zvmul(&kernel!, 1, &fft1Input, 1, &result, 1, vDSP_Length(r.count), 1)
vDSP_zvmul generates N (in your code N = vDSP_Length(r.count)) complex numbers, so you need to prepare a region which can hold N elements.
Once you call vDSP_zvmul with your current code, you break whole stack contents which causes what you have experienced:
In the debugger it seems that on the 2nd iteration of this loop, there
are no variables under the 'self' drop down.
You are hiding many parts of your code, so it is very hard to guess what you really want to do, but if I re-write your code in safer manner, it would be something like this:
func convolveInput(realsamples:[Float], imagsamples:[Float]) -> [Float]{
realResult = Array(repeating: [], count: filterbankReal.count)
imagResult = Array(repeating: [], count: filterbankReal.count)
let x = realsamples
let y = imagsamples
var N = x.count
var logN = 16
var fft1Setup = vDSP_create_fftsetup(UInt(logN), FFTRadix(FFT_RADIX2))!
var paddedLength = x.count + filterbankReal.count - 1
var halfPaddedLength = paddedLength/2
var halfKernelLength = kernelLength/2
//setup Complex Buffer 1
var reals = UnsafeMutableBufferPointer<Float>.allocate(capacity: x.count)
defer {reals.deallocate()}
var imags = UnsafeMutableBufferPointer<Float>.allocate(capacity: y.count)
defer {imags.deallocate()}
_ = reals.initialize(from: x)
_ = imags.initialize(from: y)
var complexBuffer1 = DSPSplitComplex(realp: reals.baseAddress!, imagp: imags.baseAddress!)
//Perform FFT on incoming samples
var re = UnsafeMutableBufferPointer<Float>.allocate(capacity: N)
defer {re.deallocate()}
var im = UnsafeMutableBufferPointer<Float>.allocate(capacity: N)
defer {im.deallocate()}
var fft1Input = DSPSplitComplex(realp: re.baseAddress!, imagp: im.baseAddress!)
let fftlength = 10
vDSP_fft_zop(fft1Setup, &complexBuffer1, 1, &fft1Input, 1, UInt(fftlength), Int32(FFT_FORWARD))
//Remove DC from FFT Signal
fft1Input = DSPSplitComplex(realp: re.baseAddress!+1, imagp: im.baseAddress!+1)
for i in 0..<self.fftfilterbankReal.count {
self.fftfilterbankReal[i].withUnsafeMutableBufferPointer {rBuf in
self.fftfilterbankImag[i].withUnsafeMutableBufferPointer {imBuf in
var kernel = DSPSplitComplex(realp: rBuf.baseAddress!, imagp: imBuf.baseAddress!)
var res = UnsafeMutableBufferPointer<Float>.allocate(capacity: rBuf.count)
defer {res.deallocate()}
var ims = UnsafeMutableBufferPointer<Float>.allocate(capacity: rBuf.count)
defer {ims.deallocate()}
var result:DSPSplitComplex = DSPSplitComplex(realp: res.baseAddress!, imagp: ims.baseAddress!)
vDSP_zvmul(&kernel, 1, &fft1Input, 1, &result, 1, vDSP_Length(rBuf.count), 1)
//vDSP_zvmul generates `N` complex numbers,
// I do not understand what you really want to do...
self.realResult[i].append(res[0])
self.imagResult[i].append(ims[0])
}
}
}
//...
}
There may be other parts to fix, but anyway, please try and see what you get.
Foreword: Boy, sifting through all this took me almost 2 hours, and it's still not even perfect, but boy is this much nicer. I hope it helps!
Your code is suffer massively because the Accelerate APIs are C APIs that are not adapted to take advantage of Swift features. You will have much more readable code if you make yourself some nice wrappers for the Accelerate API, which lets you tuck all the "Ugly stuff" away into a corner you seldom have to see or edit.
I did this by creating a new type, ComplexFloatArray, which is similar to DSPSplitComplex, but actually encapsulates and owns its buffers. This prevents the dangling buffers that DSPSplitComplex is susceptible to.
After dining the ComplexFloatArray types, it's time to define some wrappers for the the Accelerate functions you used. In this case, vDSP_zvmul and vDSP_fft_zop. Since C doesn't have tuples, returning multiple values from a C function usually requires that you use out-parameters, which are used pervasively in the Accelerate framework. We can re-design these as Swift functions with regular return types. These APIs are very naturally expressed as instance methods that operate on ComplexFloatArray, so we'll put them there.
Additionally, your code is made much more complex by its dependance on external state. Convolution is a function, there's no reason why it does anything besides taking in input (via parameters, and not via instance variables) and returns the result (via return value, and not via instance variables).
import Accelerate
class ComplexFloatArray {
var reals: [Float]
var imaginaries: [Float]
init(reals: [Float], imaginaries: [Float]) {
self.reals = reals
self.imaginaries = imaginaries
}
}
extension ComplexFloatArray { // Core features
var count: Int {
assert(reals.count == imaginaries.count)
return reals.count
}
static let stride = 1
func append(real: Float, imaginary: Float) {
self.reals.append(real)
self.imaginaries.append(imaginary)
}
func useAsDSPSplitComplex<R>(_ closure: (inout DSPSplitComplex) -> R) -> R {
return reals.withUnsafeMutableBufferPointer { realBufferPointer in
return imaginaries.withUnsafeMutableBufferPointer { imaginaryBufferPointer in
var dspSplitComplex = DSPSplitComplex(realp: realBufferPointer.baseAddress!, imagp: imaginaryBufferPointer.baseAddress!)
return closure(&dspSplitComplex)
}
}
}
}
extension ComplexFloatArray { // Convenience utilities
convenience init() {
self.init(reals: [], imaginaries: [])
}
static func zeros(count: Int) -> ComplexFloatArray {
return ComplexFloatArray(reals: Array(repeating: 0, count: count), imaginaries:Array(repeating: 0, count: count))
}
}
extension ComplexFloatArray { // Vector multiplciation extensions
enum ComplexMultiplicationType: Int32 { case normal = 1, conjugate = -1 }
func complexMultiply(
with other: ComplexFloatArray,
multiplicationType: ComplexMultiplicationType = .normal
) -> ComplexFloatArray {
assert(self.count == other.count, "Multiplied vectors must have the same size!")
let result = ComplexFloatArray.zeros(count: self.count)
self.useAsDSPSplitComplex { selfPointer in
other.useAsDSPSplitComplex { otherPointer in
result.useAsDSPSplitComplex { resultPointer in
vDSP_zvmul(
&selfPointer, ComplexFloatArray.stride,
&otherPointer, ComplexFloatArray.stride,
&resultPointer, ComplexFloatArray.stride, vDSP_Length(result.count),
multiplicationType.rawValue)
}
}
}
return result
}
}
extension ComplexFloatArray { // FFT extensions
enum FourierTransformDirection: Int32 { case forward = 1, inverse = -1 }
//TODO: name log2n label better
func outOfPlaceComplexFourierTransform(
setup: FFTSetup,
resultSize: Int,
log2n: UInt,
direction: FourierTransformDirection
) -> ComplexFloatArray {
let result = ComplexFloatArray.zeros(count: resultSize)
self.useAsDSPSplitComplex { selfPointer in
result.useAsDSPSplitComplex{ resultPointer in
vDSP_fft_zop(
setup,
&selfPointer, ComplexFloatArray.stride,
&resultPointer, ComplexFloatArray.stride,
log2n,
direction.rawValue
)
}
}
return result
}
}
extension FFTSetup {
enum FourierTransformRadix: Int32 {
case radix2 = 0, radix3 = 1, radix5 = 2
// Static let constants are only initialized once
// This function's intent to to make sure this enum stays in sync with the raw constants the Accelerate framework uses
static let assertRawValuesAreCorrect: Void = {
func assertRawValue(for actual: FourierTransformRadix, isEqualTo expected: Int) {
assert(actual.rawValue == expected, "\(actual) has a rawValue of \(actual.rawValue), but expected \(expected).")
}
assertRawValue(for: .radix2, isEqualTo: kFFTRadix2)
assertRawValue(for: .radix3, isEqualTo: kFFTRadix3)
assertRawValue(for: .radix5, isEqualTo: kFFTRadix5)
}()
}
init(log2n: Int, _ radix: FourierTransformRadix) {
_ = FourierTransformRadix.assertRawValuesAreCorrect
guard let setup = vDSP_create_fftsetup(vDSP_Length(log2n), FFTRadix(radix.rawValue)) else {
fatalError("vDSP_create_fftsetup(\(log2n), \(radix)) returned nil")
}
self = setup
}
}
struct NameMe {
// I don't know what this is, but if it can somehow be removed,
// the whole convolveInput method could be moved into an extension on ComplexFloatArray.
var fftFilterBank: [ComplexFloatArray]
func convolve(samples: ComplexFloatArray) -> [ComplexFloatArray] {
// TODO: rework reimplement this code to remove the DC from samples, and add it back in
// //Remove DC from FFT Signal
// re.remove(at: 0)
// im.remove(at: 0)
let fftlength: UInt = 10 // Todo: what is this, exactly?
let fft1Input = samples.outOfPlaceComplexFourierTransform( // Rename me to something better
setup: FFTSetup(log2n: 16, .radix2),
resultSize: samples.count,
log2n: fftlength,
direction: .forward
)
return self.fftFilterBank.map { kernel in kernel.complexMultiply(with: fft1Input) }
}
// Stub for compatibility with the old API. Deprecate it and move to the
// `convolve(samples: ComplexFloatArray) -> [ComplexFloatArray]` as soon as possible.
func convolveInput(realsamples: [Float], imagsamples: [Float]) -> [ComplexFloatArray] {
return self.convolve(samples: ComplexFloatArray(reals: realsamples, imaginaries: imagsamples))
}
}
I have some notes along the way
This function is WAAAAAAAAAAAY too long. If you have a function that's over 10 lines long, there's a fairly strong indicator that it's growing too large, does to many things, and could benefit from being broken down into simpler steps.
You have lots of redundant variables. You don't need more than 1 copy of any given immutable value. You have all these different names, referring to the same thing, which just complicates things. There might be an argument to be made that this can be useful if the new names have significance, but names like x, y, re, im are near-useless in their communicative ability, and should almost-always be avoided entirely.
Arrays are value types with Copy-on-Write. You can make copies of them by simply assigning to them to a new variable, so code like:
var reals = [Float]()
var imags = [Float]()
for i in 0..<x.count{
reals.append(x[i])
imags.append(y[i])
}
Is both slow, and visually cumbersome. This could be simply: let (reals, imags) = (x, y). But again, these copies are unnecessary (as are x and y). Remove them, and just use realsamples and imagsamples directly.
When you find yourself frequently passing multiple pieces of data together, that's a very strong indication that you should define a new aggregate type to wrap them. For example, if you're passing two Array<Float> to represent complex vectors, you should define a ComplexVector type. This can let you enforce invariants (e.g. there are always as many real values as imaginary values), and add convenient operations (e.g. a func append(real: Float, imaginary: Float), which operates on both simultaneously, ensuring you can never forget to append to one of the arrays).
In closing,
There's a lot going on here, so I can't possible pre-empt every question and explain it ahead of time. I encourage you to take some time, read through this, and feel free to ask me any follow up questions.
I suspect I've made mistakes during my refactor (because I had no test cases to work with), but the code is modular enough that it should be very simple to isolate and fix and bugs.

Swift: How to keep updating a Dictionary inside another Dictionary correctly?

This is a little hard to explain, but I'll try my best. I am trying to update a Dictionary inside another Dictionary properly. The following code almost does what I need.
var dictionary = Dictionary<String, [Int : Int]>()
func handleStatsValue(tag: Int ) {
let currentValue: Int = dictionary["Score"]?[tag] ?? 0
dictionary["Score"] = [
tag : currentValue + 1
]
}
However, it seems the dictionary is overridden when the tag value changes (e.g. 1 to 2). I need Dictionary to have multiple dictionaries inside of it. Any tips or suggestions are deeply appreciated.
Edit: I'm trying to have multiple dictionaries nested inside a dictionary. It seems whenever the tag value is changed, the dictionary is overridden.
One way to write this would be:
func handleStatsValue(tag: Int) {
dictionary["Score", default: [:]][tag, default: 0] += 1
}
or, written without [_:default:]
func handleStatsValue(tag: Int) {
var scoreDictionary = dictionary["Score"] ?? [:]
scoreDictionary[tag] = (scoreDictionary[tag] ?? 0) + 1
dictionary["Score"] = scoreDictionary
}
However, it's not a good idea to use nested dictionaries to keep your data. Use a custom struct instead and try to avoid tags too:
struct DataModel {
var score: [Int: Int] = [:]
}
I think you need something like this to either increase the value for an existing tag or add a new tag if it doesn't exist
func handleStatsValue(tag: Int ) {
if var innerDict = dictionary["Score"] {
if let value = innerDict[tag] {
innerDict[tag] = value + 1
} else {
innerDict[tag] = 1
}
dictionary["Score"] = innerDict
}
}
Although the code looks a bit strange with the hardcoded key "Score", maybe it would be better to have multiple simple dictionaries instead, like
var score: [Int, Int]()
or if you prefer
var score = Dictionary<Int, Int>()

Swift array basics

Gives an Index out of range eror.
Is there a syntax error or logic ?
func generateGameBoard()->([Int]){
var gboard = [Int]();
var i : Int = 0;
for(i=0;i<8;i++){
gboard[i]=1;
}
return gboard;
}
}
Dont you notice error in your code. You create an empty array and then ask index for 0 ..< 8 which is invalid. You should really use count to iterate over the contents.
func generateGameBoard()->([Int]){
var gboard = [Int]();
for i in 0 ..< gboard.count {
gboard[i]=1;
}
return gboard;
}
var gboard = [Int](); // you are creating an empty array here.
you need to append value in array
like
gboard.append(1) instead of gboard[i]=1;
and c style for loop and ++ opeartor will not use in next versions of swift.
You should also get ready for swift 3 and update the for loop part. It won't compile as it stand now in swift 3. You have to change it to:
for i in 0..<8 {
}

How to select 10 random cards (or numbers) from enum

i have some question about swift 2 random. I have an enum sub class of all cards example:
enum CardName : Int{
case Card2Heart = 0,
Card2Diamond,
Card2Club,
Card2Spade,
Card3Heart..... }
I want to select 10 random cards on the didMoveToView
To get a unique, random set of numbers you can do the following...
Using the Fisher-Yates shuffle from here... How do I shuffle an array in Swift?
You can do...
var numbers = Array(0...51)
numbers.shuffleInPlace()
let uniqueSelection = numbers[0..<10]
or...
let uniqueSelection = Array(0...51).shuffleInPlace()[0..<10]
This will create a random, unique selection of 10 numbers (cards) from the array of 52 cards that you start with.
You can then iterate this array to get the enums or create an array of all enums to start from etc... There are lots of ways to use this.
In Swift 4.2 (coming with Xcode 10) the task will become much easier:
enum CardName: CaseIterable {
case Card2Heart
case Card2Diamond
case Card2Club
case Card2Spade
case Card3Heart
// ...
}
let randomCard = CardName.allCases.randomElement()
print(randomCard)
let randomCards10 = CardName.allCases.shuffled().prefix(10)
print(randomCards10)
Note there is no need for the enum to inherit from Int.
Following your last comment, here's a little, simplified example with the constraint of having to keep your enum for making the cards.
We need to include the extensions linked by Fogmeister:
extension MutableCollectionType where Index == Int {
/// Shuffle the elements of `self` in-place.
mutating func shuffleInPlace() {
// empty and single-element collections don't shuffle
if count < 2 { return }
for i in 0..<count - 1 {
let j = Int(arc4random_uniform(UInt32(count - i))) + i
guard i != j else { continue }
swap(&self[i], &self[j])
}
}
}
extension CollectionType {
/// Return a copy of `self` with its elements shuffled
func shuffle() -> [Generator.Element] {
var list = Array(self)
list.shuffleInPlace()
return list
}
}
These extensions will allow us to shuffle an array of values.
Which array?
There's many ways, but the simplest option is probably to make an array of indices, which are simple integers (replace 52 with the actual number of cards in your enum):
Array(1...52) // [1, 2, 3, ... , 52]
We shuffle it:
Array(1...52).shuffle() // [33, 42, 7, ...]
Now we have an array of randomized indices. Let's make cards from this with your enum:
Array(0...51).shuffle().flatMap({ CardName(rawValue: $0) })
This is it, we have an array of cards in a random order:
let shuffledDeck = Array(0...51).shuffle().flatMap({ CardName(rawValue: $0) }) // [Card3Heart, Card2Diamond, ...]
and we can take cards from it:
func takeCardsFromDeck(number: Int) -> [CardName] {
if shuffledDeck.count > number {
let cards = Array(shuffledDeck[0..<number])
shuffledDeck.removeRange(0..<number)
return cards
}
return []
}
let tenRandomCards = takeCards(10)
Of course we need to remove from the deck the cards we've dealt, that way each card you draw is unique: we're using removeRange for that.
This example was kept simple on purpose: you still have to verify that there's enough cards in the deck before drawing, and lots of unsuspected other complexities. But it's so fun. ;)
If you want, you can search for additional inspiration in my implementation of these models and others (Deck, Dealer, Player, etc) in my PokerHands repository (MIT Licenced) on GitHub.
Swift 4.2
No need for these extensions anymore, we can use the .shuffle() and .shuffled() methods provided by Swift. Just remove the extensions, and rename the methods: the equivalent of our old "shuffleInPlace" is now .shuffle() and the equivalent of our old "shuffle" is now .shuffled().
Note: see Sulthan's answer for an even better solution using Swift 4.2.
Here is the shuffleInPlace() code that you are missing;
extension MutableCollectionType where Index == Int {
mutating func shuffleInPlace() {
if count < 2 { return }
for i in 0..<count - 1 {
let j = Int(arc4random_uniform(UInt32(count - i))) + i
guard i != j else { continue }
swap(&self[i], &self[j])
}
}
}
how to randomly spread enum values set
import Darwin // arc4random_uniform
enum E:Int {
case E1, E2, E3, E4, E5, E6, E7, E8, E9, E10
static var set:[E] { return (E.E1.rawValue...E.E10.rawValue).flatMap { E(rawValue: $0) }}
}
func spread(i:Int = 0, arr:[E])->([E],[E]) {
var i = i == 0 ? arr.count : i
var e:[E] = []
var arr = arr
while i > 0 && arr.count > 0 {
let idx = Int(arc4random_uniform(UInt32(arr.count-1)))
e.append(arr.removeAtIndex(idx))
i -= 1
}
return (e,arr)
}
let e1 = spread(3, arr: E.set)
let e2 = spread(2, arr: e1.1)
// ... spread the rest
let e3 = spread(arr: e2.1)
print(e1, e2, e3, separator:"\n")
/*
([E.E8, E.E6, E.E4], [E.E1, E.E2, E.E3, E.E5, E.E7, E.E9, E.E10])
([E.E1, E.E7], [E.E2, E.E3, E.E5, E.E9, E.E10])
([E.E5, E.E3, E.E2, E.E9, E.E10], [])
*/

Strange values from vDSP_meanD

I am using the vDSP_meanD function to determine the average of a data set (consecutive diferences from an array)
The code I am using is below
func F(dataAllFrames:[Double],std:Double,medida:String)->Double{
let nframes=dataAllFrames.count
var diferencas_consecutivas_media = [Double](count: dataAllFrames.count-1, repeatedValue:0.0)
var mediaDifConseq:Double = 0
for(var i:Int=1; i<dataAllFrames.count; i++){
diferencas_consecutivas_media[i-1]=dataAllFrames[i]-dataAllFrames[i-1]
}
var meanConseqDif = [Double](count: 1, repeatedValue:0.0)
var meanConseqDifPtr = UnsafeMutablePointer<Double>(meanConseqDif)
vDSP_meanvD(diferencas_consecutivas_media,1,meanConseqDifPtr,UInt(nframes))
print( meanConseqDif[0])
}
The function F is called within a thread block
let group = dispatch_group_create()
let queue = dispatch_queue_create("myqueue.data.processor", DISPATCH_QUEUE_CONCURRENT)
dispatch_group_async(group, queue) {
F(measureData,std: std, medida: medida)
}
The F function is called in multiple dispatch block with different variables instances every now and then i get different values for the value returned from vDSP_meanD is there any context where this may happen ?
May the thread call have some influence on that?
Any "lights" would be greatly appreciated
I wouldn't expect this code to work. This shouldn't be correct:
var meanConseqDif = [Double](count: 1, repeatedValue:0.0)
var meanConseqDifPtr = UnsafeMutablePointer<Double>(meanConseqDif)
vDSP_meanvD(diferencas_consecutivas_media,1,meanConseqDifPtr,UInt(nframes))
I believe this is pointing directly at the Array struct, so you're probably blowing away the metadata rather than updating the value you meant. But I would expect that you don't get the right answers at all in that case. Have you validated that your results are correct usually?
I think the code you mean is like this:
func F(dataAllFrames: [Double], std: Double, medida: String) -> Double {
let nframes = UInt(dataAllFrames.count)
var diferencas_consecutivas_media = [Double](count: dataAllFrames.count-1, repeatedValue:0.0)
for(var i = 1; i < dataAllFrames.count; i += 1) {
diferencas_consecutivas_media[i-1] = dataAllFrames[i] - dataAllFrames[i-1]
}
var mediaDifConseq = 0.0
vDSP_meanvD(diferencas_consecutivas_media, 1, &mediaDifConseq, nframes)
return mediaDifConseq
}
You don't need an output array to collect a single result. You can just use a Double directly, and use & to take an unsafe pointer to it.
Unrelated point, but you can get rid of all of the difference-generating code with a single zip and map:
let diferencasConsecutivasMedia = zip(dataAllFrames, dataAllFrames.dropFirst())
.map { $1 - $0 }
I haven't profiled these two approaches, though. It's possible that your approach is faster. I find the zip and map much clearer and less error-prone, but others may feel differently.