├── .gitignore
├── BLAS.playground
├── Sources
│ └── SupportCode.swift
├── contents.swift
├── contents.xcplayground
└── playground.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── ComplexBLAS.playground
├── Sources
│ └── SupportCode.swift
├── contents.swift
├── contents.xcplayground
└── playground.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── Compression.playground
├── Contents.swift
├── contents.xcplayground
└── playground.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── Distances.playground
├── Sources
│ └── SupportCode.swift
├── contents.swift
├── contents.xcplayground
└── playground.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── FFT.playground
├── Sources
│ └── SupportCode.swift
├── contents.swift
├── contents.xcplayground
└── playground.xcworkspace
│ └── contents.xcworkspacedata
├── LAPACK.playground
├── Sources
│ └── SupportCode.swift
├── contents.swift
├── contents.xcplayground
└── playground.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── LinearAlgebra.playground
├── Pages
│ ├── Intro.xcplaygroundpage
│ │ └── Contents.swift
│ ├── Lazy Equation Trees.xcplaygroundpage
│ │ └── Contents.swift
│ └── Solving Ax = b.xcplaygroundpage
│ │ └── Contents.swift
├── contents.xcplayground
└── playground.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── README.md
├── Schrödinger.playground
├── Resources
│ └── schrodinger.jpg
├── Sources
│ └── SupportCode.swift
├── contents.swift
├── contents.xcplayground
└── playground.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── SmoothWalker.playground
├── Contents.swift
├── contents.xcplayground
└── playground.xcworkspace
│ └── contents.xcworkspacedata
├── SparseBLAS.playground
├── Contents.swift
├── contents.xcplayground
└── playground.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── blasLookup.pdf
├── simd.playground
├── Contents.swift
├── contents.xcplayground
└── playground.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── vBigNum.playground
├── Contents.swift
├── contents.xcplayground
└── playground.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── vDSP.playground
├── Sources
│ └── SupportCode.swift
├── contents.swift
├── contents.xcplayground
└── playground.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── vForce.playground
├── Contents.swift
├── Sources
│ └── SupportCode.swift
├── contents.xcplayground
└── playground.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ └── IDEWorkspaceChecks.plist
└── vImage.playground
├── Contents.swift
├── Resources
└── boobie.png
├── contents.xcplayground
└── playground.xcworkspace
├── contents.xcworkspacedata
└── xcshareddata
└── IDEWorkspaceChecks.plist
/.gitignore:
--------------------------------------------------------------------------------
1 | project.xcworkspace
2 | xcuserdata
3 | timeline.xctimeline
4 | .DS_Store
5 |
--------------------------------------------------------------------------------
/BLAS.playground/Sources/SupportCode.swift:
--------------------------------------------------------------------------------
1 | //
2 | // This file (and all other Swift source files in the Sources directory of this playground) will be precompiled into a framework which is automatically made available to BLAS.playground.
3 | //
4 |
--------------------------------------------------------------------------------
/BLAS.playground/contents.swift:
--------------------------------------------------------------------------------
1 | /*:
2 | # Basic Linear Algebra (BLAS)
3 | _Jeff Biggus (@hyperjeff) March, 2016_
4 | */
5 | import Accelerate
6 | /*:
7 | ## Basic example: Ax + y
8 | - Note: **s** = float function, **axpy** = abbreviation for "a times x plus y"\
9 | Here we will find **10 * x + y** for a 3 element array.
10 | - Note: It's useful to add a comment above the code illustrating what you think the function is doing, because it's easy to grab the wrong function and very hard to figure out what you meant without such notes. Often there's enough room to align the math right over the variables.
11 | */
12 | var x: [Float] = [1, 2, 3]
13 | var y: [Float] = [3, 4, 5]
14 |
15 | // 10 * x + y
16 |
17 | cblas_saxpy( 3, 10, &x, 1, &y, 1 )
18 |
19 | y
20 | //: ----
21 | //:## Dot product of vectors: ∑ a[i] * b[i]
22 | //: - Note: Since the original value of **y** was overwritten by **cblas_saxpy** above, we reset it here. It's important when using values in multiple places to check and see if they were mutated by preceding functions.
23 | y = [ 3, 4, 5 ]
24 |
25 | // x • y
26 |
27 | cblas_sdot( 3, &x, 1, &y, 1 ) // == 1*3 + 2*4 + 3*5
28 | //: ----
29 | //:## Scale a vector by some value
30 | var z: [Float] = [1, 2, 3, 4, 5, 6]
31 |
32 | // 10 * z
33 |
34 | cblas_sscal(6, 10, &z, 1)
35 | z
36 |
37 | // 100 * z for every other element
38 |
39 | cblas_sscal(6, 100, &z, 2)
40 | z
41 |
--------------------------------------------------------------------------------
/BLAS.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/BLAS.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/BLAS.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ComplexBLAS.playground/Sources/SupportCode.swift:
--------------------------------------------------------------------------------
1 | //
2 | // This file (and all other Swift source files in the Sources directory of this playground) will be precompiled into a framework which is automatically made available to ComplexBLAS.playground.
3 | //
4 |
--------------------------------------------------------------------------------
/ComplexBLAS.playground/contents.swift:
--------------------------------------------------------------------------------
1 | /*:
2 | # Complex Numbers with BLAS
3 | _Jeff Biggus (@hyperjeff) March, 2016_
4 | */
5 | import Accelerate
6 | /*:
7 | ## How to use complex numbers
8 | - Note: Complex numbers are differently in different Accelerate libraries. Here, using the BLAS functions, they are represented by two floats in succession in an array. The first is the real component, the next the complex component. So each complex number is found every 2 elements in the array.
9 | - Note: When you get the result out, you are responsible for remembering that the array of floats you're left with are the complex valued results. Below the result is the array **[2,0,0,8]**, but this is code for **2 + 0i** and **0 + 8i**.
10 | */
11 | var z: [Float] = [-3, 4, 5, -7] // -3 + 4i, 5 - 7i
12 |
13 | // Ex 1: Sum of absolute value of components
14 |
15 | cblas_scasum(2, &z, 1) // |-3| + |4| + |5| + |-7| = 19
16 |
17 |
18 | var a:[Float] = [1, 2, 3, 4] // [ 1 + 2i, 3 + 4i ]
19 | var b:[Float] = [1, -2, -3, 4] // [ 1 - 2i, -3 + 4i ]
20 | var alpha: Float = 1
21 |
22 | // alpha * a + b
23 |
24 | cblas_caxpy(2, &alpha, &a, 1, &b, 1)
25 |
26 | b // [ 2 + 0i, 0 + 8 i ]
27 | /*:
28 | ## Complex Struct
29 | - Note: You can make a struct to group the complex values, as long as the only properties are the real and imaginary components, are floats, and are in the right order. But then you can add any convenience functions you'd like from there.
30 | */
31 | struct Complex: CustomStringConvertible {
32 | var real: Float
33 | var imag: Float
34 |
35 | var description: String {
36 | let threshold: Float = 0.00000001
37 |
38 | if fabsf(real) > threshold && fabsf(imag) > threshold {
39 | return "\(real) + \(imag) i"
40 | } else if fabsf(imag) > threshold {
41 | return "\(imag) i"
42 | } else {
43 | return "\(real) + 0 i"
44 | }
45 | }
46 | }
47 |
48 | var c: [Complex] = [Complex(real: 1, imag: 2), Complex(real: 3, imag: 4)]
49 | var d: [Complex] = [Complex(real: 1, imag:-2), Complex(real:-3, imag: 4)]
50 |
51 | // alpha * c + d
52 |
53 | cblas_caxpy( 2, &alpha, &c, 1, &d, 1 )
54 |
55 | d[0]
56 | d[1]
57 | /*:
58 | ## Variation Using a Postfix Operator
59 | - Note: The above struct makes the code very wordy. One can clean up the code by actually making something like the "i" above into an operator. Here, instead of using the letter (which you can't turn into an operator anyway), we make use of the **¡** (an inverted exclamation mark, easily typed using option-1). This makes the code look very much like standard math notation.
60 | */
61 | postfix operator ¡
62 | postfix func ¡ (x: Float) -> Complex {
63 | return Complex(real: 0, imag: x)
64 | }
65 | infix operator +
66 | func + (left: Float, right: Complex) -> Complex {
67 | return Complex(real: left + right.real, imag: right.imag)
68 | }
69 | infix operator -
70 | func - (left: Float, right: Complex) -> Complex {
71 | return Complex(real: left - right.real, imag: -1 * right.imag)
72 | }
73 |
74 | var e: [Complex] = [1 + 2¡, 3 + 4¡]
75 | var f: [Complex] = [1 - 2¡, -3 + 4¡]
76 |
77 | cblas_caxpy(2, &alpha, &e, 1, &f, 1)
78 |
79 | f[0]
80 | f[1]
81 | /*:
82 | ## Dot product of complex vectors:
83 | - Note: Type-completion hint as of Xcode 7.3, since it now does fuzzy string completion: To find the BLAS dot product function without wading thru the documentation, start by typing "blas" then type "dot" and right away you're down to a selection of 4 versions of the dot product. Season to taste from there.
84 | */
85 | var g: [Complex] = [1 + 2¡, 3 + 4¡]
86 | var h: [Complex] = [1 - 2¡, -3 + 4¡]
87 |
88 | var gDotH: Complex = 0¡
89 |
90 | // g • h -> gDotH = ∑ g[i] * h[i]
91 |
92 | cblas_cdotu_sub(2, &g, 1, &h, 1, &gDotH)
93 |
94 | gDotH // 1 + 4 - 9 - 16 = -20
95 |
--------------------------------------------------------------------------------
/ComplexBLAS.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/ComplexBLAS.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ComplexBLAS.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Compression.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | /*:
2 | # Compression
3 | _Jeff Biggus (@hyperjeff) March, 2016_
4 | */
5 | import Compression
6 | /*:
7 | lossless data compression\
8 | high speed + energy efficiency
9 |
10 | 4 compressors:
11 | * lz4 (fastest)
12 | * lzfse (bit faster and a touch better compression than zlib)
13 | * zlib (standard)
14 | * lzma (slower but best compression)
15 |
16 | All optimzed on Apple hardware, so better than just using usual zlib
17 | */
18 | let source:[UInt8] = [1, 4, 9, 8, 6, 3, 0, 2, 9, 2]
19 | let destinationCapacity = size_t(30)
20 | var destination = [UInt8](unsafeUninitializedCapacity: Int(destinationCapacity), initializingWith: {_, _ in})
21 |
22 | let destinationSize = compression_encode_buffer(&destination, destinationCapacity, source, source.count, nil, COMPRESSION_LZFSE)
23 |
24 | destination
25 |
26 | var returnBuffer = [UInt8](unsafeUninitializedCapacity: source.count, initializingWith: {_, _ in})
27 |
28 | compression_decode_buffer(&returnBuffer, source.count, destination, destinationSize, nil, COMPRESSION_LZFSE)
29 |
30 | returnBuffer
31 | /*:
32 | - Note: If the destination capacity in the above example is set below 23, the LZFSE compression is not possible, and you are left with all zeros. So, make sure you have enough room.
33 | ----
34 | ## Buffer and Streaming APIs
35 | That is the simple buffer API.
36 | From here there is a streaming API version that works asynchronously while your app is doing something, where you can check on the status and wrap things up when it's finished. You will need to also set up a scratch buffer for the compressor to work with.
37 | */
38 |
--------------------------------------------------------------------------------
/Compression.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Compression.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Compression.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Distances.playground/Sources/SupportCode.swift:
--------------------------------------------------------------------------------
1 | //
2 | // This file (and all other Swift source files in the Sources directory of this playground) will be precompiled into a framework which is automatically made available to Distances.playground.
3 | //
4 |
--------------------------------------------------------------------------------
/Distances.playground/contents.swift:
--------------------------------------------------------------------------------
1 | /*:
2 | # vDSP: Distances Along a 2-d Path
3 | _Jeff Biggus (@hyperjeff) March, 2016_
4 | */
5 | import Cocoa
6 | import Accelerate
7 |
8 | var points:[CGPoint] = [
9 | CGPoint(x: -40, y: 0),
10 | CGPoint(x: 35, y: 40),
11 | CGPoint(x: 30, y: 70),
12 | CGPoint(x: 110, y: 20),
13 | CGPoint(x: 10, y: -10),
14 | CGPoint(x: -20, y: -70),
15 | CGPoint(x: -110, y: -20),
16 | CGPoint(x: 20, y: -40),
17 | CGPoint(x: 0, y: 0)
18 | ]
19 |
20 | let path = NSBezierPath()
21 | path.move(to: points[0])
22 | for i in 1..
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Distances.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Distances.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/FFT.playground/Sources/SupportCode.swift:
--------------------------------------------------------------------------------
1 | //
2 | // This file (and all other Swift source files in the Sources directory of this playground) will be precompiled into a framework which is automatically made available to Accelerate- FFT.playground.
3 | //
4 |
--------------------------------------------------------------------------------
/FFT.playground/contents.swift:
--------------------------------------------------------------------------------
1 | /*:
2 | # vDSP: Fast Fourier Transforms
3 | _Jeff Biggus (@hyperjeff) March, 2016_
4 | */
5 | import Accelerate
6 | //:## Setup. See section down below to see what the input signals are and how to customize them
7 | //:- Note: Here we will make use of **stride1** and **stride2** constants. We could just pop a 1 and a 2 in the functions below, but the functions are sufficiently complicated that the variable name helps keep straight what values go where and why.
8 | enum InputSignal {
9 | case Noise, Sine, Sines, NoisySinesA, NoisySinesB, NoisySinesC, NoisySinesD, NoisySinesE
10 | }
11 | func floats(_ n: Int)->[Float] {
12 | return [Float](repeating: 0.0, count: n)
13 | }
14 | var ƒ: (Float) -> Float
15 | func frandom() -> Float { return Float(arc4random()) / Float( RAND_MAX ) }
16 | let stride1: vDSP_Stride = 1
17 | let stride2:vDSP_Stride = 2
18 | //:## Pick your signal and pick your sample size:
19 | let signal: InputSignal = .Sine
20 | let sampleSize = 2000
21 | //:## A little more setup, now that we have the signal and sample size
22 | //:- Note: We'll use the ramp function to use for making sine waves
23 | let sampleLength = vDSP_Length(sampleSize)
24 | var start: Float = 0
25 | var increment: Float = 1
26 | var ramp = floats( sampleSize )
27 | vDSP_vramp( &start, &increment, &ramp, stride1, vDSP_Length( sampleSize ) )
28 | var data = floats(sampleSize)
29 | //:## Define how each signal is created
30 | do {switch signal {
31 | case .Sine: ƒ = { sin( $0 / 3 ) }
32 | case .Sines: ƒ = { sin( $0 / 3 ) * sin( $0 / 6 ) * sin( $0 / 12 ) }
33 | case .Noise: ƒ = { frandom() + $0 - $0 }
34 | case .NoisySinesA: ƒ = { sin( $0 / 3 ) + frandom() / 2 }
35 | case .NoisySinesB: ƒ = { sin( $0 / 3 ) + 0.5 * sin( $0 / 1 ) + frandom() }
36 | case .NoisySinesC: ƒ = { frandom() * sin( $0 / 3 ) }
37 | case .NoisySinesD: ƒ = { frandom() * sin( $0 ) * sin( 4 * $0 ) * sin( 4 * $0 ) }
38 | case .NoisySinesE: ƒ = { frandom() * (ceil( sin( $0 / 3 ) ) - 0.5) }
39 | }}
40 | data = ramp.map( ƒ )
41 | data[0..<200].map { $0 }
42 | //:## Set up for doing an FFT
43 | //:- Note: The FFT functions use a _Split Complex_ data type, which places the real and imaginary components in two separate arrays, below is an example of how to work with these.
44 | let log2n: vDSP_Length = vDSP_Length(log2f(Float(sampleSize)))
45 | let fftSetup = vDSP_create_fftsetup(log2n, FFTRadix(FFT_RADIX2))!
46 | let nOver2 = sampleSize/2
47 | let nOver2Length = vDSP_Length(nOver2)
48 | var real = floats(nOver2)
49 | var imaginary = floats(nOver2)
50 | real.withUnsafeMutableBufferPointer {realBP in
51 | imaginary.withUnsafeMutableBufferPointer {imaginaryBP in
52 | var splitComplex = DSPSplitComplex(realp: realBP.baseAddress!, imagp: imaginaryBP.baseAddress!)
53 |
54 | //:## Calculate a 1-d real-valued, discrete Fourier transform, from time domain to frequency domain
55 | //:- Note: This is perhaps the most unusual part. We grab a pointer to the data's baseAddress.
56 | data.withUnsafeBufferPointer { buffer in
57 | buffer.baseAddress!.withMemoryRebound(to: DSPComplex.self, capacity: buffer.count / 2) { body in
58 | vDSP_ctoz(body, stride2, &splitComplex, stride1, nOver2Length)
59 | vDSP_fft_zrip(fftSetup, &splitComplex, stride1, log2n, FFTDirection(FFT_FORWARD))
60 | }
61 | }
62 |
63 | //:## Take a look at the amplitudes of the frequencies
64 | let amplitudeCount = sampleSize / 10
65 | var amplitudes = floats( amplitudeCount )
66 |
67 | vDSP_zvmags( &splitComplex, stride1, &litudes, stride1, vDSP_Length( amplitudeCount ) )
68 |
69 | amplitudes[0] = splitComplex.realp[0] / Float(sampleSize * 2)
70 | amplitudes.map { $0 }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/FFT.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/FFT.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/LAPACK.playground/Sources/SupportCode.swift:
--------------------------------------------------------------------------------
1 | //
2 | // This file (and all other Swift source files in the Sources directory of this playground) will be precompiled into a framework which is automatically made available to LAPACK.playground.
3 | //
4 |
--------------------------------------------------------------------------------
/LAPACK.playground/contents.swift:
--------------------------------------------------------------------------------
1 | /*:
2 | # LAPACK: Linear Algebra Package
3 | _Jeff Biggus (@hyperjeff) March, 2016_
4 | */
5 | import Accelerate
6 | typealias LAInt = __CLPK_integer // = Int32
7 | /*:
8 | ## Solving A x = b for x
9 | - Example:
10 | Idea: Solving simultaneous equations.
11 |
12 | 3x + y + 2z = -1\
13 | x + 5y + 6z = 3\
14 | 3x + 9y + 5z = -3
15 |
16 | Question: what's x, y and z?
17 | - Note: The way A is set up may look flipped (LAPACK convention)
18 | - Note: LAPACK functions are particularly horribly named, but there is a good resource for finding your way around on the [LAPACK Site](http://www.netlib.org/lapack/explore-html/).
19 | - Note: The output is very often over-writes one of the variables passed in, so if you need to use that thing later, make yourself a copy.
20 | */
21 | var A:[Float] = [
22 | 3, 1, 3,
23 | 1, 5, 9,
24 | 2, 6, 5
25 | ]
26 |
27 | var b:[Float] = [ -1, 3, -3 ]
28 |
29 | let equations = 3
30 |
31 | var numberOfEquations:LAInt = 3
32 | var columnsInA: LAInt = 3
33 | var elementsInB: LAInt = 3
34 | var bSolutionCount: LAInt = 1
35 |
36 | var outputOk: LAInt = 0
37 | var pivot = [LAInt](unsafeUninitializedCapacity: equations, initializingWith: {_, _ in})
38 |
39 | sgesv_( &numberOfEquations, &bSolutionCount, &A, &columnsInA, &pivot, &b, &elementsInB, &outputOk)
40 |
41 | outputOk // 0 = everything went ok
42 |
43 | pivot // this gives an information about how the equations were solved
44 |
45 | b // this is our answer (it over-writes its original value)
46 | //:### Now to show the solutions really work:
47 | 3 * b[0] + b[1] + 2 * b[2]
48 | b[0] + 5 * b[1] + 6 * b[2]
49 | 3 * b[0] + 9 * b[1] + 5 * b[2]
50 | //:### the solution is good!
51 |
--------------------------------------------------------------------------------
/LAPACK.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/LAPACK.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/LAPACK.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/LinearAlgebra.playground/Pages/Intro.xcplaygroundpage/Contents.swift:
--------------------------------------------------------------------------------
1 | /*:
2 | # Linear Algebra
3 | ## Part of the Accelerate Framework
4 | _Jeff Biggus (@hyperjeff) March, 2016_
5 |
6 | [Start](@next)
7 | */
8 |
--------------------------------------------------------------------------------
/LinearAlgebra.playground/Pages/Lazy Equation Trees.xcplaygroundpage/Contents.swift:
--------------------------------------------------------------------------------
1 | /*:
2 | [Previous](@previous)
3 | # Equation Trees and Lazy Evaluation
4 | _Jeff Biggus (@hyperjeff) March, 2016_
5 | */
6 | import Accelerate
7 |
8 | var aSourceOfFloats: [Float] = [1,2,3,4,5,6]
9 |
10 | let aAsMatrix = la_matrix_from_float_buffer( &aSourceOfFloats, 1, 6, 6, 0, 0 )
11 |
12 | let aVector = la_vector_from_matrix_row(aAsMatrix, 0)
13 |
14 | var aCheckOnThatVector = [Float](repeating: 0, count: 6)
15 |
16 | la_vector_to_float_buffer(&aCheckOnThatVector, 1, aVector)
17 |
18 | aCheckOnThatVector
19 |
20 | // ahhhh... ok, a pain, but it works. Get the data in, get it out.
21 | /*:
22 | ### So let's turn that into a convenient function (why isn't there one?)
23 | */
24 | func la_vector(_ vector: [Float]) -> la_object_t {
25 | var floats = vector
26 | let count = la_count_t(floats.count)
27 | let floatsAsMatrix = la_matrix_from_float_buffer( &floats, 1, count, count, 0, 0 )
28 | return la_vector_from_matrix_row(floatsAsMatrix, 0)
29 | }
30 |
31 | func vectorAsFloats(_ vector: la_object_t) -> [Float] {
32 | var vectorAsFloats = [Float](repeating: 0, count: Int(la_vector_length(vector)))
33 | la_vector_to_float_buffer(&vectorAsFloats, 1, vector)
34 | return vectorAsFloats
35 | }
36 |
37 | let a = la_vector([1,2,3,4,5,6,7,8,9])
38 | let b = la_vector([9,8,7,6,5,4,3,2,1])
39 |
40 | let c = la_sum(a, b)
41 |
42 | vectorAsFloats(c)
43 | /*:
44 | ### Yes, that was a terrible payoff for all that work. Continuing on...
45 | */
46 | let d = la_scale_with_float(b, 10)
47 |
48 | let e = la_inner_product(c, d)
49 |
50 | let f = la_vector_slice(a, 2, 3, 3)
51 |
52 | vectorAsFloats(f)
53 | /*:
54 | - Note: Nothing is actually computed until you ask to transfer the data in the LA objects into a buffer. Above, that happens each time with run **vectorAsFloats**. But, as with blocks, we can set up an arbitrarily long chain of functions which do something, but don't actually do any evaluating until the whole chain is set off by a request to put the result into the buffer. This also has the nice side effect of not evaluating anything that doesn't need to be.
55 | */
56 |
--------------------------------------------------------------------------------
/LinearAlgebra.playground/Pages/Solving Ax = b.xcplaygroundpage/Contents.swift:
--------------------------------------------------------------------------------
1 | /*:
2 | [Previous](@previous) | [Next](@next)
3 | # LinearAlgebra: Solivng A x = b for x
4 | _Jeff Biggus (@hyperjeff) March, 2016_
5 | */
6 | import Accelerate
7 | //: - Note: A is transposed from how it has to be with LAPACK!
8 | var A: [Float] = [
9 | 3, 1, 2,
10 | 1, 5, 6,
11 | 3, 9, 5
12 | ]
13 |
14 | var b: [Float] = [ -1, 3, -3 ]
15 | var x = [Float](repeating: 0.0, count: 3)
16 | //: ### First transform A and b into the world of LinearAlgebra objects (la_object_t)
17 | let count1 = la_count_t(1) // to help with clarity
18 | let count3 = la_count_t(3)
19 | let index1 = la_index_t(1)
20 |
21 | let A™ = la_matrix_from_float_buffer( &A, count3, count3, count3, 0, 0 )
22 | let b™ = la_matrix_from_float_buffer( &b, count3, count1, count1, 0, 0 )
23 |
24 | let x™ = la_solve( A™, b™ )
25 | //: ### Then we transfer the number back into the world of Floats
26 | let status = la_vector_to_float_buffer( &x, index1, x™ )
27 |
28 | x // our answer! It's over there ➤
29 | /*:
30 | - Note: Returning LA objects give you a status update on how things went
31 | - Note: You can pass "hints" to the above matrix maker, in order to tell it, for instance, type of matrix (symmetric, diagonal, etc), which also helps performance. In the above, 0 = LA_NO_HINT.
32 | - Note: You can also pass attribute information. In the above, 0 = default attributes. You can also enable logging.
33 | - Note: It is best to delay error checking until the very end, because it triggers any not-yet-done computations, and any code above will gracefully propagate its errors down the equation graph. The debug logging in the last note lets you track down where any problems happened in the chain.
34 | */
35 | if status == 0 {
36 | "Worked!"
37 | } else if status > 0 {
38 | "Worked, but accuracy is poor"
39 | } else {
40 | "FAILED"
41 | }
42 | /*:
43 | - Note: Variables accessed by reference (A, b, x) have to be var-iable.
44 | - Note: LA objects don't need to be mutable unless, ya know, you want to mutate them.
45 | */
46 |
--------------------------------------------------------------------------------
/LinearAlgebra.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/LinearAlgebra.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/LinearAlgebra.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Accelerate Playgrounds!
2 |
3 | This is collection of Swift playgrounds that illustrate how to leverage Apple's Accelerate framework in Swift for performance.
4 |
5 | Currently these are for Xcode 11 / Swift 5 and above. (Check out earlier versions if you have an older system. It started out as a Swift 2.x project.)
6 |
7 | Learn and have fun, but please don't just plagiarize and present the work as your own (this happened to this playground, in fact). If you use the code for an article or similar, you must make sure to include due credit to this author and a link back to this repository. Ideally, make up your own completely different set of examples. Contribute to the community.
8 |
9 |
10 | Many thanks to [Brad Howes](https://github.com/bradhowes) and [Rahul Bhalley](https://github.com/rahulbhalley) for their fixes to bring it up to date with Swift 5; very much appreciated.
11 |
--------------------------------------------------------------------------------
/Schrödinger.playground/Resources/schrodinger.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hyperjeff/Accelerate-in-Swift/b1f1cf7850c73ebf8dfdc94ef6ccbefc83768d23/Schrödinger.playground/Resources/schrodinger.jpg
--------------------------------------------------------------------------------
/Schrödinger.playground/Sources/SupportCode.swift:
--------------------------------------------------------------------------------
1 | //
2 | // This file (and all other Swift source files in the Sources directory of this playground) will be precompiled into a framework which is automatically made available to Schrödinger.playground.
3 | //
4 |
--------------------------------------------------------------------------------
/Schrödinger.playground/contents.swift:
--------------------------------------------------------------------------------
1 | /*:
2 | # LAPACK: Schrödinger Solutions for 1-d Square Well
3 | _Jeff Biggus (@hyperjeff) March, 2016_
4 | - Note: The makes use of the work done here: http://physics-simulation.blogspot.com/2007/10/solving-schrodinger-equation-linear.html
5 | */
6 | import Accelerate
7 | typealias LAInt = __CLPK_integer
8 |
9 | let N = 80
10 | let dx = 10 / Double(N)
11 | let dx² = dx * dx
12 |
13 | var hDiag = Array(repeating: 0, count: N)
14 | var hOff = Array(repeating: -1, count: N)
15 | var v = Array(repeating: 0, count: N)
16 | var work = Array(repeating: 0, count: 2 * N)
17 | var z = Array(repeating: 0, count: N * N)
18 |
19 | var n: LAInt = LAInt(N-1)
20 | var ldz: LAInt = n
21 | var info: LAInt = 0
22 | var jobType: Int8 = 86 // = "V" in ASCII
23 |
24 | for i in 0..
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Schrödinger.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Schrödinger.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/SmoothWalker.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | /*:
2 | # Using vDSP: Smooth out a Random Path
3 | _Jeff Biggus (@hyperjeff) March, 2016_
4 | */
5 | import Cocoa
6 | import Accelerate
7 |
8 | var points: [CGPoint] = [.zero]
9 |
10 | func randomNudge() -> CGPoint {
11 | return CGPoint(x: CGFloat(Int(arc4random_uniform(101)) - 50) / 5.0,
12 | y: CGFloat(Int(arc4random_uniform(101)) - 50) / 5.0)
13 | }
14 |
15 | // infix operator +
16 | // infix operator /
17 |
18 | func + (left: CGPoint, right:CGPoint) -> CGPoint {
19 | return CGPoint(x: left.x + right.x, y: left.y + right.y)
20 | }
21 | func / (left: CGPoint, right: Float) -> CGPoint {
22 | return CGPoint(x: left.x / CGFloat(right), y: left.y / CGFloat(right))
23 | }
24 |
25 | var v = CGPoint.zero
26 |
27 | for _ in 0...99 {
28 | let p = points.last!
29 | v = randomNudge() + (v / 1.2)
30 | points.append(CGPoint(x: p.x + v.x, y: p.y + v.y))
31 | }
32 |
33 | let path = NSBezierPath()
34 | points.withUnsafeBufferPointer { buffer in
35 | buffer.baseAddress!.withMemoryRebound(to: NSPoint.self, capacity: points.count) { nsp in
36 | path.appendPoints(NSPointArray(mutating: nsp), count: points.count)
37 | }
38 | }
39 |
40 | path
41 | // tease out the x and y values
42 | let xs: [Float] = points.map { Float($0.x) }
43 | let ys: [Float] = points.map { Float($0.y) }
44 |
45 | // set up a variable to hold the result
46 | var distance = [Float](repeating: 0, count: points.count)
47 |
48 | // one-liner!
49 | vDSP_vdist(xs, 1, ys, 1, &distance, 1, vDSP_Length(points.count))
50 |
51 | // display
52 | distance.map { $0 }
53 | var maximumX: Float = 0
54 | var minimumX: Float = 0
55 |
56 | vDSP_maxv(xs, 1, &maximumX, vDSP_Length(points.count))
57 | vDSP_minv(xs, 1, &minimumX, vDSP_Length(points.count))
58 |
59 | maximumX
60 | minimumX
61 |
62 | let windowSize: Int = 5
63 |
64 | var smoothXs = [Float](repeating: 0, count: points.count)
65 | var smoothYs = [Float](repeating: 0, count: points.count)
66 | let window = vDSP_Length(windowSize)
67 |
68 | vDSP_vswsum(xs, 1, &smoothXs, 1, vDSP_Length(points.count), window)
69 | vDSP_vswsum(ys, 1, &smoothYs, 1, vDSP_Length(points.count), window)
70 |
71 | let smoothXsGuts = smoothXs[0 ..< points.count - windowSize - 1]
72 | xs.map { $0 }
73 | smoothXsGuts.map { $0 }
74 |
75 | var smoothPoints: [CGPoint] = []
76 | for i in 0 ..< smoothXs.count - windowSize - 1 {
77 | let x = CGFloat(smoothXs[i] / 5)
78 | let y = CGFloat(smoothYs[i] / 5)
79 | smoothPoints.append(CGPoint(x: x, y: y))
80 | }
81 |
82 | let smoothPath = NSBezierPath()
83 | smoothPoints.withUnsafeBufferPointer { buffer in
84 | buffer.baseAddress!.withMemoryRebound(to: NSPoint.self, capacity: smoothPoints.count) { nsp in
85 | smoothPath.appendPoints(NSPointArray(mutating: nsp), count: smoothPoints.count)
86 | }
87 | }
88 |
89 | path
90 | smoothPath
91 |
--------------------------------------------------------------------------------
/SmoothWalker.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/SmoothWalker.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/SparseBLAS.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | /*:
2 | # Sparse BLAS
3 | _Jeff Biggus (@hyperjeff) March, 2016_
4 |
5 | ----
6 | ## BLAS for Sparse matrices
7 | - Note: Introduces in 2015 for iOS 9 and Mac OS X 10.10.
8 | - Note: Single and Double precision operations: products, triangular solves, norms, traces, permutations, inserts & extracts. Many storage formats available. Uses a sparse matrix data type.
9 |
10 | */
11 | import Accelerate
12 | /*:
13 | ## Sparse Matrix Data Type
14 | - Note: Manages data buffer, storage format and dimension details for you.
15 | */
16 | var A = sparse_matrix_create_float(3700, 4041)
17 |
18 | // insert a single value
19 |
20 | sparse_insert_entry_float(A, 15, 2874, 1798)
21 |
22 | // insert a whole row or column of stuff at once
23 |
24 | let rowValues:[Float] = [ 3, 9, 7 ]
25 | let rowIndices:[sparse_index] = [ 937, 1599, 2300 ]
26 |
27 | let status = sparse_insert_row_float(A, 1100, 3, rowValues, rowIndices)
28 |
29 | status.rawValue
30 | //: From here, you can operate on the matrices as with BLAS.
--------------------------------------------------------------------------------
/SparseBLAS.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/SparseBLAS.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/SparseBLAS.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/blasLookup.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hyperjeff/Accelerate-in-Swift/b1f1cf7850c73ebf8dfdc94ef6ccbefc83768d23/blasLookup.pdf
--------------------------------------------------------------------------------
/simd.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | /*:
2 | # simd: Single Instruction, Multiple Data
3 | _Jeff Biggus (@hyperjeff) March, 2016_
4 | ### Introduced in 2014 for use with Metal, but also very useful on its own. It's available for iOS 8 and OS X 10.10 on up.
5 | * Support 2, 3 and 4-d math & geometry.
6 | * Floats, doubles, 32-bit ints (signed & unsigned), long vectors and unaligned vectors supported.
7 | * Uses normal operators + - * / (etc) to work on vectors and matrices.
8 | * There are conversion functions to change types
9 | * Has uniform function names to work on different sized objects.
10 | * Provide Metal-esque feature parity. Helpful for prototyping Metal code.
11 | * Works great with other libraries like ModelIO, Metal, SpriteKit, etc.
12 | ----
13 | */
14 | import simd
15 | /*:
16 | ----
17 | ### Convenient and frequently useful data types
18 | - Note: The component labels are optional
19 | */
20 | let geoLocation = SIMD2(x: 15.1231, y: -23.846)
21 |
22 | let voxelLocation = SIMD3(3, -2, 4)
23 |
24 | let spacetimeLocation = SIMD4(x: 2, y: 5, z: 3, w: -1)
25 |
26 | let specialRelativitySpacetimeMetric = float4x4([
27 | [1, 0, 0, 0],
28 | [0, 1, 0, 0],
29 | [0, 0, 1, 0],
30 | [0, 0, 0,-1]
31 | ])
32 |
33 | spacetimeLocation * specialRelativitySpacetimeMetric * spacetimeLocation
34 | /*:
35 | ----
36 | ### Grabbing components via properties or indexes
37 | */
38 | geoLocation[0]
39 | geoLocation.x
40 |
41 | voxelLocation[2]
42 | voxelLocation.z
43 |
44 | spacetimeLocation[3]
45 | spacetimeLocation.w
46 | /*:
47 | ----
48 | ### Easier ways to do common functions without needing to roll your own:
49 | */
50 | let x = SIMD3(repeating: 2) // one argument makes all components to the value
51 | let y = SIMD3(5, 6, 7)
52 |
53 | x + 3 * y
54 |
55 | dot(x, y) // 2 * 5 + 2 * 6 + 2 * 7 = 36
56 |
57 | cross(x, y)
58 |
59 | reflect(x, n: y) // reflect the vector x in the plane defined by the normal vector y
60 | /*:
61 | ----
62 | ## Matrices
63 | Lots of standard functions available.
64 | - Note: Matrices are (columns) x (rows). This is the opposite of most math / science books, but some graphics programming texts use this ordering and it leaked into some (but by no means all) real world code. Why they decided to go down this path is a historical accident we are stuck with. This means the order of operations may be the opposite of what you expect or read in a source text. Re-ordering and transposing can get things right.
65 | */
66 | let m = float3x2([ // collection of *columns*
67 | [1, 2],
68 | [3, 4],
69 | [5, 6]
70 | ])
71 |
72 | m
73 | m.transpose
74 |
75 | geoLocation * m
76 | m.transpose * geoLocation
77 |
78 | abs(geoLocation)
79 | max(voxelLocation, SIMD3(repeating: -5))
80 | max(abs(voxelLocation), abs(SIMD3(repeating: -5)))
81 | clamp(voxelLocation, min: SIMD3(repeating: -1), max: SIMD3(repeating: 2))
82 |
83 | smoothstep(SIMD3(repeating: -10), edge0: SIMD3(repeating: 10), edge1: voxelLocation)
84 | //: - Note: There are fats and precise versions of several functions. Make sure to actually check on the precision that you need in your apps and then make a choice about which functions to use.
85 | simd_fast_recip(geoLocation)
86 | simd_precise_recip(geoLocation)
87 |
88 | simd_fast_recip(geoLocation) * geoLocation
89 | simd_precise_recip(geoLocation) * geoLocation
90 | /*:
91 | ----
92 | - Note: There may be times when you need to interoperate with other parts of the system that insist on, say, a vector_float4 instead of a float4, or a matrix_float4x4 instaed of float4x4. Just convert to the other type and be happy.
93 | */
94 |
--------------------------------------------------------------------------------
/simd.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/simd.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/simd.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/vBigNum.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | /*:
2 | # vBigNum: 128 to 1024-bit Integer functions
3 | - Note: 2^1024 is ~224 *orders of magnitude* greater than (someone's) estimate of the number of particles in the univers. Used in Crypto a lot.
4 | */
5 | import Accelerate
6 | /*:
7 | ### Here we'll make a bunch of 1024-bit integers. They are represented by structs that contain 32 32-bit integers, the lowest is the LSW (least significant word) and the highest is the MSW (most significant word). You set their values, then use vBigNum functions to manipulate.
8 | - Note: 2^1024 =\
9 | 179_769_313_486_231_590_772_930_519_078_902_473_361_797_697_894_230_657_273_430_081_157_732_675_805_500_963_132_708_477_322_407_536_021_120_113_879_871_393_357_658_789_768_814_416_622_492_847_430_639_474_124_377_767_893_424_865_485_276_302_219_601_246_094_119_453_082_952_085_005_768_838_150_682_342_462_881_473_913_110_540_827_237_163_350_510_684_586_298_239_947_245_938_479_716_304_835_356_329_624_224_137_216
10 | */
11 | var a: vS1024 = vS1024()
12 | var b: vS1024 = vS1024()
13 | var c: vS1024 = vS1024()
14 | var d: vS1024 = vS1024()
15 | var e: vS1024 = vS1024()
16 | var f: vS1024 = vS1024()
17 | //:## First example, encode the numbers 1 and 3, add, then divide them:
18 | a.s.LSW = 1
19 | b.s.LSW = 3
20 |
21 | vS1024Add(&a, &b, &c)
22 |
23 | "\(a.s.LSW) + \(b.s.LSW) = \(c.s.LSW)"
24 |
25 | vS1024Divide(&a, &b, &d, &e)
26 |
27 | "\(a.s.LSW) / \(b.s.LSW) = \(d.s.LSW) remainder \(e.s.LSW)"
28 | //:## Now a *huge* number: 2^1023 divided by 3
29 | f.s.MSW = 1
30 |
31 | vS1024Divide(&f, &b, &d, &e) // f / b
32 |
33 | d.s.MSW
34 | d.s.d2 // 1431655765 = UInt32.max / 3
35 | d.s.d3
36 | // etc
37 | d.s.d10
38 | // etc
39 | d.s.d31
40 | d.s.LSW
41 |
42 | e.s.LSW // (the higher struct parts of e are 0)
43 | /*:
44 | - Note: Fun (?) analogy:\
45 | Just as 1_000_000/3 = 333_333 remainder 1\
46 | which is (1/3) * 10^6 + (1/3) * 10^5 + ... (1/3) * 10^1 + 1\
47 | so also this is "just"\
48 | (1/3) * (UInt32.max)^31 + (1/3) * (UInt32.max)^30 + ... + 1\
49 | i.e., 1_431_655_765 is just the 1/3rd number in base 4_294_967_296
50 | */
--------------------------------------------------------------------------------
/vBigNum.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/vBigNum.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/vBigNum.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/vDSP.playground/Sources/SupportCode.swift:
--------------------------------------------------------------------------------
1 | //
2 | // This file (and all other Swift source files in the Sources directory of this playground) will be precompiled into a framework which is automatically made available to vDSP.playground.
3 | //
4 |
--------------------------------------------------------------------------------
/vDSP.playground/contents.swift:
--------------------------------------------------------------------------------
1 | /*:
2 | # vDSP: Audio, but also much more
3 | _Jeff Biggus (@hyperjeff) March, 2016_
4 | */
5 | import Accelerate
6 |
7 | var data:[Float]
8 | var output:[Float]
9 | var count: vDSP_Length
10 | /*:
11 | ## Example 1: Create a nice ramp of data
12 | - Note: Despite many places in functions where it looks like you should be able to just pop a number in there, often you have to send in the variable as a reference, as with the **start** and **increment** numbers below. Option-clicking the function in Xcode will show which items need to be references, typed as some kind of pointer.
13 | - Note: As with most functions in the Accelerate framework, functions do not return anything. You pass in a reference to a _var_ variable and go from there.
14 | */
15 | count = 10
16 | var start: Float = -3
17 | var increment: Float = 0.1
18 | var ramp = [Float](unsafeUninitializedCapacity:Int(count), initializingWith: {_, _ in})
19 |
20 | vDSP_vramp( &start, &increment, &ramp, 1, count )
21 |
22 | ramp.map { $0 }
23 | /*:
24 | ## Example 2: Absolute values
25 | - Note: The **length** is always required to be of **vDSP_Length** type, as so you need to cast it. This used to be the case with strides as well, but now we can just put a nice **1** in there. Perhaps some day we can do that with lengths. That said, this does prevent us from mixing up items passed to the functions, arguments very easily mixed up.
26 | */
27 | data = [0,0,0,0,9,-4,7,10,6,-8,9,-14,3,-4,-6,-8,8,7,4,2,0,0,0,0]
28 |
29 | data.map { $0 }
30 |
31 | count = vDSP_Length(data.count)
32 | output = [Float](unsafeUninitializedCapacity:Int(count), initializingWith: {_, _ in})
33 |
34 | vDSP_vabs( &data, 1, &output, 1, count )
35 |
36 | output.map { $0 }
37 |
38 | //:## Example 4: Clipping
39 | var low: Float = 2.5
40 | var high:Float = 4.5
41 |
42 | vDSP_vclip( &data, 1, &low, &high, &output, 1, count )
43 |
44 | output.map { $0 }
45 | /*:
46 | ## Example 5: Reversing
47 | - Note: If you're even on a job interview and someone asks you to reverse an array of floats, you can tell them that I said the following function is all you need to know.
48 | */
49 | vDSP_vrvrs(&data, 1, count)
50 |
51 | data.map { $0 }
52 | //:## Example 6: Maximum value
53 | var maximum: Float = 0
54 | var mean: Float = 0
55 | var rms: Float = 0
56 | var sum: Float = 0
57 |
58 | vDSP_maxv(&data, 1, &maximum, count); maximum
59 |
60 | vDSP_meanv(&data, 1, &mean, count); mean
61 |
62 | vDSP_rmsqv(&data, 1, &rms, count); rms
63 |
64 | vDSP_sve(&data, 1, &sum, count); sum
65 |
66 |
--------------------------------------------------------------------------------
/vDSP.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/vDSP.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/vDSP.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/vForce.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | /*:
2 | # vForce: Standard Math on Arrays
3 | _Jeff Biggus (@hyperjeff) March, 2016_
4 | */
5 | import Accelerate
6 |
7 | func floats(n: Int32) -> [Float] {
8 | return [Float](repeating: 0.0, count: Int(n))
9 | }
10 | /*:
11 | ## Example: Absolute values
12 | - Note: Docs claim **y[i] = abs(x[i]-1)**, but it's actually **abs(x[i])**. Lesson: Docs are fallible. (But do file doc radars.)
13 | - Note: "count" needs to be Int32, not just Int
14 | */
15 | var count: Int32 = 4
16 | var a: [Float] = [3, -2, 5, -10]
17 | var aAbsolute = floats(n: count)
18 |
19 | vvfabsf(&aAbsolute, &a, &count)
20 |
21 | aAbsolute
22 | /*:
23 | ## Example: Integers from Floats
24 | - Note: Sometimes NO variables in the docs at all!
25 | */
26 | count = 3
27 | var b: [Float] = [3.3796, 1.8036, -2.1205]
28 | var bInt = floats(n: count)
29 |
30 | vvintf(&bInt, &b, &count)
31 |
32 | bInt
33 | //:## Example: Square Roots
34 | count = 4
35 | var c:[Float] = [16, 9, 4, 1]
36 | var cSquareRoots = floats(n: count)
37 |
38 | vvsqrtf(&cSquareRoots, &c, &count)
39 |
40 | cSquareRoots
41 | //:## Example: Flipping Numbers Over
42 | count = 4
43 | var d:[Float] = [1/3, 2/5, 1/8, -3/1]
44 | var dFlipped = floats(n: count)
45 |
46 | vvrecf(&dFlipped, &d, &count)
47 |
48 | dFlipped
49 | //:## Example: Taking a Sine
50 | let π: Float = 355/113
51 | count = 100
52 | var ramp = floats(n: count)
53 | var rampStart: Float = 0
54 | var rampIncrease: Float = 1 / (5 * π) // Float(count) / (2 * π)
55 |
56 | var rampSin = floats(n: count)
57 |
58 | vDSP_vramp(&rampStart, &rampIncrease, &ramp, 1, vDSP_Length(count))
59 | ramp
60 |
61 | vvsinpif(&rampSin, &ramp, &count)
62 |
63 | rampSin.map { $0 }
64 | //:## Act _now_ and we'll throw in this _Cosine_ for free!
65 | var rampCos = floats(n: count)
66 | rampIncrease = 1 / 5
67 | vDSP_vramp(&rampStart, &rampIncrease, &ramp, 1, vDSP_Length(count))
68 | ramp
69 |
70 | vvsincosf(&rampSin, &rampCos, &ramp, &count)
71 |
72 | rampSin.map { $0 }
73 |
74 | rampCos.map { $0 }
75 | /*:
76 | - Note: The input values are off by a factor of π from the other function! _(Not mentioned in the docs.)_
77 | */
78 |
--------------------------------------------------------------------------------
/vForce.playground/Sources/SupportCode.swift:
--------------------------------------------------------------------------------
1 | //
2 | // This file (and all other Swift source files in the Sources directory of this playground) will be precompiled into a framework which is automatically made available to MyPlayground.playground.
3 | //
4 |
--------------------------------------------------------------------------------
/vForce.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/vForce.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/vForce.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/vImage.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | import Cocoa
2 | import CoreImage
3 | import Accelerate
4 | import PlaygroundSupport
5 |
6 | let cookiesURL = NSURL(fileURLWithPath: Bundle.main.pathForImageResource("boobie.png")!)
7 | let imageSource = CGImageSourceCreateWithURL(cookiesURL, nil)
8 | let image = CGImageSourceCreateImageAtIndex(imageSource!, 0, nil)!
9 |
10 | let width = image.width
11 | let height = image.height
12 | let bytesPerRow = image.bytesPerRow
13 | let size = NSMakeSize(CGFloat(width), CGFloat(height))
14 |
15 | let nsImage = NSImage(cgImage: image, size: size)
16 | var frame = NSMakeRect(0, 0, 0, 0)
17 | frame.size = size
18 | let playgroundView = NSImageView(frame: frame)
19 | playgroundView.image = nsImage
20 |
21 | let colorSpace = CGColorSpaceCreateDeviceRGB()
22 | var backgroundColor : Array = [0,0,0,0]
23 | let fillBackground: vImage_Flags = UInt32(kvImageBackgroundColorFill)
24 |
25 | func doStuff() {
26 | guard let inProvider = image.dataProvider else { return }
27 | let providerCopy = inProvider.data
28 | let inBitmapData = UnsafeMutableRawPointer(mutating: CFDataGetBytePtr(providerCopy))
29 |
30 | var inBuffer = vImage_Buffer(data: inBitmapData, height: UInt(height), width: UInt(width), rowBytes: bytesPerRow)
31 |
32 | let pixelBuffer = malloc(bytesPerRow * height)
33 |
34 | var midBuffer = vImage_Buffer(data: pixelBuffer, height: UInt(height), width: UInt(width), rowBytes: bytesPerRow)
35 | var outBuffer = vImage_Buffer(data: pixelBuffer, height: UInt(height), width: UInt(width), rowBytes: bytesPerRow)
36 |
37 | // Kernel close to Apple's example in their vImage Programming Guide
38 |
39 | let kernel:[Int16] = [
40 | -2, -2, 1,
41 | -2, 6, 0,
42 | 1, 0, 0
43 | ]
44 |
45 | vImageConvolve_ARGB8888(&inBuffer, &midBuffer, nil, 0, 0, kernel, 3, 3, 3, &backgroundColor, fillBackground)
46 |
47 | vImageRotate_ARGB8888(&midBuffer, &inBuffer, nil, 20, &backgroundColor, fillBackground)
48 |
49 | vImageHorizontalReflect_ARGB8888(&inBuffer, &outBuffer, fillBackground)
50 |
51 | guard let context = CGContext(data: outBuffer.data, width: width, height: height, bitsPerComponent: 8, bytesPerRow: outBuffer.rowBytes, space: colorSpace, bitmapInfo: CGImageAlphaInfo.noneSkipLast.rawValue) else { return }
52 |
53 | let outCGimage = context.makeImage()
54 |
55 | playgroundView.image = NSImage(cgImage: outCGimage!, size: size)
56 |
57 | free(pixelBuffer)
58 | }
59 |
60 | class Controller: NSViewController {
61 |
62 | override func mouseDown(with event: NSEvent) {
63 | doStuff()
64 | }
65 |
66 | override func mouseUp(with event: NSEvent) {
67 | playgroundView.image = nsImage
68 | }
69 | }
70 |
71 | let controller = Controller()
72 | controller.view = playgroundView
73 |
74 | PlaygroundPage.current.liveView = playgroundView
75 | PlaygroundPage.current.needsIndefiniteExecution = true
76 |
--------------------------------------------------------------------------------
/vImage.playground/Resources/boobie.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hyperjeff/Accelerate-in-Swift/b1f1cf7850c73ebf8dfdc94ef6ccbefc83768d23/vImage.playground/Resources/boobie.png
--------------------------------------------------------------------------------
/vImage.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/vImage.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/vImage.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------