├── .build
├── build.db
├── debug
│ └── MultilinearMath.build
│ │ ├── master.swiftdeps
│ │ ├── main.swiftdeps
│ │ └── output-file-map.json
└── debug.yaml
├── Resources
├── BackpropGraph.jpg
├── MNIST_compression_pca.jpg
├── Slicing3dFlat_table.jpg
├── MNIST_compression_mpca.jpg
├── MNIST_compression_umpca.jpg
├── MNIST_compression_original.jpg
├── MultilinearDataUnfolding.jpg
├── NestedVsMultidimensional.jpg
├── SlicingTwoModes3dFlat_table.jpg
└── ExampleTextFile.rtf
├── Package.swift
├── Playgrounds
├── FFTPlayground.playground
│ ├── contents.xcplayground
│ └── Contents.swift
├── TestPlayground.playground
│ ├── contents.xcplayground
│ └── Contents.swift
├── MyPlayground.playground
│ ├── contents.xcplayground
│ └── Contents.swift
├── ComplexWavelets.playground
│ ├── contents.xcplayground
│ └── Contents.swift
├── DB2VanishingMoments.playground
│ ├── contents.xcplayground
│ └── Contents.swift
├── DB4VanishingMoments.playground
│ ├── contents.xcplayground
│ └── Contents.swift
├── DB6VanishingMoments.playground
│ ├── contents.xcplayground
│ └── Contents.swift
├── WaveletPacketTransform.playground
│ ├── contents.xcplayground
│ └── Contents.swift
├── WaveletReassignment.playground
│ ├── contents.xcplayground
│ └── Contents.swift
└── WaveletPlayground.playground
│ ├── contents.xcplayground
│ └── Contents.swift
├── MultilinearMathWS.xcworkspace
└── contents.xcworkspacedata
├── MultilinearMath.xcodeproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
└── xcuserdata
│ └── vincentherrmann.xcuserdatad
│ └── xcschemes
│ ├── xcschememanagement.plist
│ ├── MultilinearMathTests.xcscheme
│ ├── MultilinearMath.xcscheme
│ ├── MultilinearMath 2.xcscheme
│ └── MultilinearMathExample.xcscheme
├── FastWaveletTransform.playground
├── contents.xcplayground
└── Contents.swift
├── MultilinearMath
├── MultilinearMath.h
└── Info.plist
├── MultilinearMathTests
├── Info.plist
├── PlotTests.swift
├── FourierTransformTests.swift
├── MultidimensionalDataTests.swift
├── MultilinearMathTests.swift
├── DataSlicingTests.swift
├── NeuralNetTests.swift
├── DispatchPerformaceTests.swift
├── AccelerateFunctionTests.swift
└── WaveletTests.swift
├── Sources
├── ActivationFunctions.swift
├── FIRFilter.swift
├── BoundingProtocols.swift
├── DataSetLoading.swift
├── LinearRegression.swift
├── Optimization.swift
├── WaveletPlots.swift
├── LogisticRegression.swift
├── TensorSyntacticOperators.swift
├── DaubechiesWavelets.swift
├── ComplexNumbers.swift
├── ComplexWavelets.swift
├── WaveletCreation.swift
├── TensorOperationNodes.swift
├── MPCA.swift
├── ParametricFunctions.swift
├── Utilities.swift
└── NeuralNetwork.swift
└── README.md
/.build/build.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincentherrmann/multilinear-math/HEAD/.build/build.db
--------------------------------------------------------------------------------
/Resources/BackpropGraph.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincentherrmann/multilinear-math/HEAD/Resources/BackpropGraph.jpg
--------------------------------------------------------------------------------
/Resources/MNIST_compression_pca.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincentherrmann/multilinear-math/HEAD/Resources/MNIST_compression_pca.jpg
--------------------------------------------------------------------------------
/Resources/Slicing3dFlat_table.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincentherrmann/multilinear-math/HEAD/Resources/Slicing3dFlat_table.jpg
--------------------------------------------------------------------------------
/Resources/MNIST_compression_mpca.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincentherrmann/multilinear-math/HEAD/Resources/MNIST_compression_mpca.jpg
--------------------------------------------------------------------------------
/Resources/MNIST_compression_umpca.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincentherrmann/multilinear-math/HEAD/Resources/MNIST_compression_umpca.jpg
--------------------------------------------------------------------------------
/Resources/MNIST_compression_original.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincentherrmann/multilinear-math/HEAD/Resources/MNIST_compression_original.jpg
--------------------------------------------------------------------------------
/Resources/MultilinearDataUnfolding.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincentherrmann/multilinear-math/HEAD/Resources/MultilinearDataUnfolding.jpg
--------------------------------------------------------------------------------
/Resources/NestedVsMultidimensional.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincentherrmann/multilinear-math/HEAD/Resources/NestedVsMultidimensional.jpg
--------------------------------------------------------------------------------
/Resources/SlicingTwoModes3dFlat_table.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vincentherrmann/multilinear-math/HEAD/Resources/SlicingTwoModes3dFlat_table.jpg
--------------------------------------------------------------------------------
/Resources/ExampleTextFile.rtf:
--------------------------------------------------------------------------------
1 | {\rtf1\ansi\ansicpg1252\cocoartf949
2 | {\fonttbl}
3 | {\colortbl;\red255\green255\blue255;}
4 | \margl1440\margr1440\vieww9000\viewh8400\viewkind0
5 | }
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | import PackageDescription
2 |
3 | let package = Package(name: "MultilinearMath",
4 | targets: [],
5 | dependencies: [])
6 |
7 |
--------------------------------------------------------------------------------
/Playgrounds/FFTPlayground.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Playgrounds/TestPlayground.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/MultilinearMathWS.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/MultilinearMath.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/FastWaveletTransform.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Playgrounds/MyPlayground.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Playgrounds/ComplexWavelets.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Playgrounds/DB2VanishingMoments.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Playgrounds/DB4VanishingMoments.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Playgrounds/DB6VanishingMoments.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Playgrounds/WaveletPacketTransform.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Playgrounds/WaveletReassignment.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Playgrounds/WaveletPlayground.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Playgrounds/FFTPlayground.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | //: Playground - noun: a place where people can play
2 |
3 | import Cocoa
4 | import MultilinearMath
5 |
6 | //setup nodes
7 | //let forwardFFT = FourierTransform(modeSizes: [4, 4])
8 | //let inverseFFT = InverseFourierTransform(modeSizes: [4, 4])
9 | //
10 | //let inputSignal = randomTensor(modeSizes: 2, 4, 4).uniquelyIndexed()
11 | //let transformedSignal = forwardFFT.execute([inputSignal])
12 |
13 | let a: [Float] = [0, -2, 2.0]
14 | let quickLook = QuickArrayPlot(array: a)
15 | let bounds = quickLook.plotView.plottingBounds
16 | //let p = quickLook.plotView.plots[0].plotBounds
17 |
--------------------------------------------------------------------------------
/MultilinearMath/MultilinearMath.h:
--------------------------------------------------------------------------------
1 | //
2 | // MultilinearMath.h
3 | // MultilinearMath
4 | //
5 | // Created by Vincent Herrmann on 29.03.16.
6 | // Copyright © 2016 Vincent Herrmann. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for MultilinearMath.
12 | FOUNDATION_EXPORT double MultilinearMathVersionNumber;
13 |
14 | //! Project version string for MultilinearMath.
15 | FOUNDATION_EXPORT const unsigned char MultilinearMathVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/MultilinearMathTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/MultilinearMath/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 0.0.1
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSHumanReadableCopyright
24 | Copyright © 2016 Vincent Herrmann. All rights reserved.
25 | NSPrincipalClass
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/MultilinearMathTests/PlotTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PlotTests.swift
3 | // MultilinearMath
4 | //
5 | // Created by Vincent Herrmann on 12.08.16.
6 | // Copyright © 2016 Vincent Herrmann. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import MultilinearMath
11 |
12 | class PlotTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testQuickLook() {
25 | let a: [Float] = [2.0, -1.0, 4.0, 1.0]
26 | let quickLook = QuickArrayPlot(array: a)
27 | let q = quickLook.customPlaygroundQuickLook
28 | }
29 |
30 | func testExample() {
31 | // This is an example of a functional test case.
32 | // Use XCTAssert and related functions to verify your tests produce the correct results.
33 | }
34 |
35 | func testPerformanceExample() {
36 | // This is an example of a performance test case.
37 | self.measure {
38 | // Put the code you want to measure the time of here.
39 | }
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/.build/debug/MultilinearMath.build/master.swiftdeps:
--------------------------------------------------------------------------------
1 | version: "Apple Swift version 3.0-dev (LLVM b010debd0e, Clang 3e4d01d89b, Swift 7182c58cb2)"
2 | options: "b2375201e0462b7219dbf580d9b392b4"
3 | build_time: [512471670, 417517000]
4 | inputs:
5 | "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/Sources/AccelerateFunctionsFloat.swift": !dirty [512422800, 0]
6 | "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/Sources/main.swift": !dirty [512422395, 0]
7 | "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/Sources/MPCA.swift": !dirty [512425649, 0]
8 | "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/Sources/MultidimensionalData.swift": !dirty [512469549, 0]
9 | "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/Sources/SlicingSubscripts.swift": !dirty [512422951, 0]
10 | "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/Sources/TensorMultiplication.swift": !dirty [512423052, 0]
11 | "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/Sources/TensorOperations.swift": !dirty [512423462, 0]
12 | "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/Sources/Tensors.swift": !dirty [512422994, 0]
13 | "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/Sources/UMPCA.swift": !dirty [512425680, 0]
14 | "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/Sources/Utilities.swift": !dirty [512431554, 0]
15 |
--------------------------------------------------------------------------------
/MultilinearMathTests/FourierTransformTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FourierTransformTests.swift
3 | // MultilinearMath
4 | //
5 | // Created by Vincent Herrmann on 05.08.16.
6 | // Copyright © 2016 Vincent Herrmann. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import MultilinearMath
11 |
12 | class FourierTransformTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testFFTNodes() {
25 | //setup nodes
26 | let forwardFFT = FourierTransform(modeSizes: [3, 7])
27 | let inverseFFT = InverseFourierTransform(modeSizes: [3, 7])
28 |
29 | let inputSignal = randomTensor(modeSizes: 2, 3, 7).uniquelyIndexed()
30 | print("original signal: \(inputSignal.values)")
31 | let transformedSignal = forwardFFT.execute([inputSignal])
32 | let reconstructedSignal = inverseFFT.execute(transformedSignal)[0]
33 | print("reconstructed signal: \(reconstructedSignal.values)")
34 |
35 | let factor = reconstructedSignal.values[0] / inputSignal.values[0]
36 | print("scaling factor for sizes \(inputSignal.modeSizes): \(factor)")
37 |
38 | let mse = meanSquaredError(target: inputSignal.values, result: reconstructedSignal.values)
39 | print("mse: \(mse)")
40 | XCTAssert(mse < 0.01, "no acceptable reconstruction from fourier transform")
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/Playgrounds/TestPlayground.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | //: Playground - noun: a place where people can play
2 |
3 | import Cocoa
4 | import MultilinearMath
5 |
6 | let inputData = zeros(20, 4, 5)
7 | let projectionModeSizes = [3, 3]
8 |
9 | let data = inputData.uniquelyIndexed()
10 | let sampleModeCount = data.modeCount-1
11 |
12 | var projectionMatrices: [Tensor] = []
13 | let projectionModeIndices = TensorIndex.uniqueIndexArray(sampleModeCount, excludedIndices: data.indices)
14 |
15 | for n in 0..(diagonalWithModeSizes: modeSizes, repeatedValue: 1.0)
18 | thisProjectionMatrix.indices = [projectionModeIndices[n], data.indices[n+1]]
19 | projectionMatrices.append(thisProjectionMatrix)
20 | }
21 |
22 | public func multilinearPCAProjectionP(data data: Tensor, projectionMatrices: [Tensor], doNotProjectModes: [Int] = []) -> Tensor {
23 |
24 | var currentData = data
25 | for n in 0..(modeSizes: [2, 3, 4], values: Array(0..<24).map({return Float($0)}))
26 | //var b = Tensor(scalar: 1.0)
27 |
28 | var indices: [TensorIndex] = [.a, .b, .c]
29 | t.indices = indices
30 |
31 | var reorderedT = t.reorderModes([2, 0, 1])
32 | XCTAssertEqual(t[0, 1, 2], reorderedT[2, 0, 1], "random order")
33 |
34 |
35 | t = Tensor(modeSizes: [2, 3, 4, 5, 6, 7], values: Array(0..<5040).map({return Float($0)}))
36 | indices = [.a, .b, .c, .d, .e, .f]
37 | t.indices = indices
38 |
39 | reorderedT = t.reorderModes([0, 1, 2, 4, 3, 5])
40 | XCTAssertEqual(t[0, 1, 2, 3, 4, 5], reorderedT[0, 1, 2, 4, 3, 5], "swap .d and .e")
41 |
42 | reorderedT = t.reorderModes([4, 5, 0, 2, 3, 1])
43 | XCTAssertEqual(t[0, 1, 2, 3, 4, 5], reorderedT[4, 5, 0, 2, 3, 1], "random order")
44 |
45 | reorderedT = t.reorderModes([5, 4, 3, 2, 1, 0])
46 | XCTAssertEqual(t[0, 1, 2, 3, 2, 1], reorderedT[1, 2, 3, 2, 1, 0], "inverse order")
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/MultilinearMath.xcodeproj/xcuserdata/vincentherrmann.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | MultilinearMath 2.xcscheme
8 |
9 | isShown
10 |
11 | orderHint
12 | 1
13 |
14 | MultilinearMath.xcscheme
15 |
16 | isShown
17 |
18 | orderHint
19 | 0
20 |
21 | MultilinearMathExample.xcscheme
22 |
23 | orderHint
24 | 4
25 |
26 | MultilinearMathTests.xcscheme
27 |
28 | orderHint
29 | 2
30 |
31 |
32 | SuppressBuildableAutocreation
33 |
34 | BA0BE4641CCAA81D0024F368
35 |
36 | primary
37 |
38 |
39 | BA275E0E1CAAD3B100B1FEC3
40 |
41 | primary
42 |
43 |
44 | BA275E171CAAD3B200B1FEC3
45 |
46 | primary
47 |
48 |
49 | BA3EFBC51CAB12FA00F723D4
50 |
51 | primary
52 |
53 |
54 | BA5D85DA1CAA7A03002D142F
55 |
56 | primary
57 |
58 |
59 | BA67AE581CA86C3E009906F2
60 |
61 | primary
62 |
63 |
64 | BA8FD7B31CA91CDC005A9986
65 |
66 | primary
67 |
68 |
69 | BAC83E341CAAD61400290119
70 |
71 | primary
72 |
73 |
74 | BAC83E3D1CAAD61500290119
75 |
76 | primary
77 |
78 |
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/MultilinearMathTests/MultilinearMathTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MultilinearMathTests.swift
3 | // MultilinearMathTests
4 | //
5 | // Created by Vincent Herrmann on 29.03.16.
6 | // Copyright © 2016 Vincent Herrmann. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import MultilinearMath
11 |
12 | class MultilinearMathTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testExample() {
25 | // This is an example of a functional test case.
26 | // Use XCTAssert and related functions to verify your tests produce the correct results.
27 |
28 | var testArray: [Float] = []
29 | let reduceTest1 = testArray.reduce(1, {$0*$1})
30 | testArray = [1.0]
31 | let reduceTest2 = testArray.reduce(1, {$0*$1})
32 | testArray = [2.0, 1.0, 0.0]
33 | let reduceTest3 = testArray.reduce(1, {$0*$1})
34 |
35 | }
36 |
37 | func testPerform() {
38 |
39 | print("")
40 | let tensor = Tensor(modeSizes: [2, 3, 2], values: Array(0..<12).map({return Float($0)}))
41 | let sum1 = sum(tensor, overModes: [0])
42 | XCTAssertEqual(sum1.values, [6.0, 8.0, 10.0, 12.0, 14.0, 16.0], "sum over mode 0")
43 | print("")
44 | let sum2 = sum(tensor, overModes: [1])
45 | XCTAssertEqual(sum2.values, [6.0, 9.0, 24.0, 27.0], "sum over mode 1")
46 | print("")
47 | let sum3 = sum(tensor, overModes: [0, 1])
48 | XCTAssertEqual(sum3.values, [30.0, 36.0], "sum over mode 0 and 1")
49 | print("")
50 | let sum4 = sum(tensor, overModes: [0, 1, 2])
51 | XCTAssertEqual(sum4.values, [66.0], "sum over mode 0")
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/Sources/ActivationFunctions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ActivationFunctions.swift
3 | // MultilinearMath
4 | //
5 | // Created by Vincent Herrmann on 19.06.16.
6 | // Copyright © 2016 Vincent Herrmann. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public protocol ActivationFunction {
12 | func output(_ input: Tensor) -> Tensor
13 | func derivative(_ input: Tensor) -> Tensor
14 | }
15 |
16 | public struct Sigmoid: ActivationFunction {
17 | public func output(_ input: Tensor) -> Tensor {
18 | let values = input.values.map { (x) -> Float in
19 | if x >= 0 {
20 | return 1 / (1 + (exp(-x)))
21 | } else {
22 | let e = exp(x)
23 | return e / (1 + e)
24 | }
25 | }
26 | let tensor = Tensor(withPropertiesOf: input, values: values)
27 | return tensor
28 | //return 1 / (1 + exp(-input)) //this method would be numerically unstable
29 | }
30 | public func derivative(_ input: Tensor) -> Tensor {
31 | let s = output(input)
32 | let result = s °* (1-s)
33 | return result
34 | }
35 | }
36 |
37 | public struct ReLU: ActivationFunction {
38 | public var secondarySlope: Float
39 |
40 | public init(secondarySlope: Float) {
41 | self.secondarySlope = secondarySlope
42 | }
43 |
44 | public func output(_ input: Tensor) -> Tensor {
45 | return Tensor(withPropertiesOf: input, values: input.values.map({max(secondarySlope*$0, $0)}))
46 | }
47 | public func derivative(_ input: Tensor) -> Tensor {
48 | return Tensor(withPropertiesOf: input, values: input.values.map({$0 > 0 ? 1.0 : secondarySlope}))
49 | }
50 | }
51 |
52 | public struct Softplus: ActivationFunction {
53 | public func output(_ input: Tensor) -> Tensor {
54 | let output = log(1 + exp(input))
55 | return output
56 | }
57 | public func derivative(_ input: Tensor) -> Tensor {
58 | let expo = exp(input)
59 | let der = expo °/ (1 + expo)
60 | return der
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/MultilinearMath.xcodeproj/xcuserdata/vincentherrmann.xcuserdatad/xcschemes/MultilinearMathTests.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
14 |
15 |
17 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
39 |
40 |
41 |
42 |
48 |
49 |
51 |
52 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/Sources/FIRFilter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FIRFilter.swift
3 | // MultilinearMath
4 | //
5 | // Created by Vincent Herrmann on 15.08.16.
6 | // Copyright © 2016 Vincent Herrmann. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public struct FIRFilter {
12 | public var coefficients: [Float]
13 | public var order: Int {
14 | get {return coefficients.count}
15 | }
16 |
17 | public init(coefficients: [Float]) {
18 | self.coefficients = coefficients
19 | }
20 |
21 | public func zTransform(_ z: ComplexNumber) -> ComplexNumber {
22 | // print("z transform at: \(z)")
23 | var x: ComplexNumber = 0 + i*0
24 | for n in 0.. ComplexNumber {
35 | return zTransform(cos(omega) + (i*sin(omega)))
36 | }
37 |
38 | public func frequencyResponse(resolution: Int = 100) -> (response: [ComplexNumber], frequencies: [Float]) {
39 | let xArray = Array(0.. (r: Float, i: Float) {
47 | return (a.0 + b.0, a.1 + b.1)
48 | }
49 |
50 | public func substractComplex(a: (Float, Float), b: (Float, Float)) -> (r: Float, i: Float) {
51 | return (a.0 - b.0, a.1 - b.1)
52 | }
53 |
54 | public func multiplyComplex(_ a: (Float, Float), b: (Float, Float)) -> (r: Float, i: Float) {
55 | let r = a.0 * b.0 - a.1 * b.1
56 | let i = a.1 * b.0 + a.0 * b.1
57 | return (r, i)
58 | }
59 |
60 | public func divideComplex(a: (Float, Float), b: (Float, Float)) -> (r: Float, i: Float) {
61 | let den = b.0 * b.0 + b.1 * b.1
62 | let r = (a.0 * b.0 + a.1 * b.1) / den
63 | let i = (a.1 * b.0 - a.0 * b.1) / den
64 | return (r, i)
65 | }
66 |
67 | public func powComplex(_ z: (Float, Float), n: Int) -> (r: Float, i: Float) {
68 | if(n == 0) {
69 | return (1, 0)
70 | }
71 |
72 | let m = n<0 ? -n : n
73 | var r: (Float, Float) = (1, 0)
74 | for _ in 0.. 0) {
80 | return r
81 | } else {
82 | let denom = r.0*r.0 + r.1*r.1
83 | return(r.0/denom, -r.1/denom)
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/MultilinearMathTests/DataSlicingTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DataSlicingTests.swift
3 | // MultilinearMath
4 | //
5 | // Created by Vincent Herrmann on 29.03.16.
6 | // Copyright © 2016 Vincent Herrmann. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import MultilinearMath
11 |
12 | class DataSlicingTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testArrayBasedFastSlicing() {
25 | var originalTensor = zeros(5, 5, 5)
26 | let sliceTensor = ones(2, 3, 2)
27 | let subscripts: [DataSliceSubscript] = [[2, 4], [0, 1, 3], [1, 4]]
28 |
29 | //copyIndices(subscripts, modeSizes: [5, 5, 5])
30 | originalTensor.values.withUnsafeMutableBufferPointer { (pointer) -> () in
31 | //
32 | copySliceFrom(sliceTensor, to: originalTensor, targetPointer: pointer, subscripts: subscripts, copyFromSlice: true)
33 | }
34 |
35 | }
36 |
37 | func testRangeSlicing() {
38 | var testData = Tensor(modeSizes: [3, 4, 5], values: Array(0..<60).map({return Float($0)}))
39 |
40 | let testSlice1 = testData[1..<2, 3..<4, 2..<5]
41 | let compareValues1: [Float] = [37, 38, 39]
42 | XCTAssertEqual(testSlice1.values, compareValues1, "data slice 1D")
43 |
44 | let testSlice2 = testData[0...1, 2...2, 1...2]
45 | let compareValues2: [Float] = [11, 12, 31, 32]
46 | XCTAssertEqual(testSlice2.values, compareValues2, "data slice 2D")
47 |
48 | let testSlice3 = testData[1...2, [0, 1, 2], 3...4]
49 | let compareValues3: [Float] = [23, 24, 28, 29, 33, 34, 43, 44, 48, 49, 53, 54]
50 | XCTAssertEqual(testSlice3.values, compareValues3, "data slice 3D")
51 |
52 | let testSlice4 = testData[0..<1, 0..<4, 0..<1]
53 | let compareValues4: [Float] = [0, 5, 10, 15]
54 | XCTAssertEqual(testSlice4.values, compareValues4, "data slice with variadic subscript")
55 |
56 | let slice = Tensor(modeSizes: [2, 3, 2], values: Array(0..<12).map({return Float($0)}))
57 | testData[0...1, 1...3, [1, 4]] = slice
58 | XCTAssertEqual(testData[0, 1, 1], 0, "slice replacement 1")
59 | XCTAssertEqual(testData[0, 1, 4], 1, "slice replacement 2")
60 | XCTAssertEqual(testData[0, 2, 1], 2, "slice replacement 3")
61 | XCTAssertEqual(testData[1, 3, 4], 11, "slice replacement 4")
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/MultilinearMathTests/NeuralNetTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NeuralNetTests.swift
3 | // MultilinearMath
4 | //
5 | // Created by Vincent Herrmann on 13.06.16.
6 | // Copyright © 2016 Vincent Herrmann. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import MultilinearMath
11 |
12 | class NeuralNetTests: XCTestCase {
13 |
14 | func testMNISTClassification() {
15 | print("load MNIST data...")
16 | let rawData = loadMNISTImageFile("/Users/vincentherrmann/Documents/Software/DataSets/MNIST/train-images-2.idx3-ubyte")
17 | let rawLabels = loadMNISTLabelFile("/Users/vincentherrmann/Documents/Software/DataSets/MNIST/train-labels.idx1-ubyte")
18 | print("normalize...")
19 | let data = normalize(Tensor(modeSizes: [rawData.modeSizes[0], 28*28], values: rawData.values), overModes: [0]).normalizedTensor
20 | let labels = createOneHotVectors(rawLabels.map({Int($0)}), differentValues: Array(0...9))
21 | let trainingData = data[0..<50000, all]
22 | let trainingLabels = labels[0..<50000, all]
23 | let validationData = data[50000..<60000, all]
24 | let validationLabels = rawLabels[50000..<60000].map({Float($0)})
25 |
26 | let estimator = NeuralNet(layerSizes: [28*28, 40, 10])
27 | estimator.layers[0].activationFunction = ReLU(secondarySlope: 0.01)
28 | estimator.layers[1].activationFunction = ReLU(secondarySlope: 0.01)
29 | let neuralNetCost = SquaredErrorCost(forEstimator: estimator)
30 | let regularizer = ParameterDecay(decayRate: 0.0001)
31 | neuralNetCost.regularizers[0] = regularizer
32 | neuralNetCost.regularizers[2] = regularizer
33 |
34 | let epochs = 30
35 | stochasticGradientDescent(neuralNetCost, inputs: trainingData[.a, .b], targets: trainingLabels[.a, .c], updateRate: 0.1, minibatchSize: 50, validationCallback: ({ (epoch, estimator) -> (Bool) in
36 | print("epoch \(epoch)")
37 |
38 | let estimate = estimator.output(validationData)
39 | let maximumIndices = findMaximumElementOf(estimate, inMode: 1)
40 | let correctValues = zip(validationLabels, maximumIndices.values).filter({$0.0 == $0.1})
41 | print("classified \(correctValues.count) of \(validationLabels.count) correctly")
42 | if(epoch >= epochs) {
43 | return true
44 | } else {
45 | return false
46 | }
47 | }))
48 |
49 | let testBatch = validationData[0..<10, all]
50 | let finalEstimate = neuralNetCost.estimator.output(testBatch)
51 | print("finalEstimate: \(finalEstimate.values)")
52 | let maximumIndices = findMaximumElementOf(finalEstimate, inMode: 1)
53 | print("max indices: \(maximumIndices.values)")
54 | let target = Array(validationLabels[0..<10])
55 | print("targets: \(target)")
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/.build/debug/MultilinearMath.build/main.swiftdeps:
--------------------------------------------------------------------------------
1 | ### Swift dependencies file v0 ###
2 | provides-top-level:
3 | provides-nominal:
4 | provides-member:
5 | provides-dynamic-lookup:
6 | depends-top-level:
7 | - "print"
8 | - "StringLiteralType"
9 | depends-member:
10 | depends-nominal:
11 | depends-dynamic-lookup:
12 | depends-external:
13 | - "/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-03-24-a.xctoolchain/usr/lib/swift/macosx/x86_64/Swift.swiftmodule"
14 | - "/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-03-24-a.xctoolchain/usr/lib/swift/shims/Visibility.h"
15 | - "/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-03-24-a.xctoolchain/usr/lib/swift/shims/UnicodeShims.h"
16 | - "/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-03-24-a.xctoolchain/usr/lib/swift/shims/RuntimeStubs.h"
17 | - "/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-03-24-a.xctoolchain/usr/lib/swift/shims/SwiftStdint.h"
18 | - "/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-03-24-a.xctoolchain/usr/lib/swift/shims/SwiftStddef.h"
19 | - "/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-03-24-a.xctoolchain/usr/lib/swift/shims/RuntimeShims.h"
20 | - "/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-03-24-a.xctoolchain/usr/lib/swift/shims/LibcShims.h"
21 | - "/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-03-24-a.xctoolchain/usr/lib/swift/shims/RefCount.h"
22 | - "/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-03-24-a.xctoolchain/usr/lib/swift/shims/HeapObject.h"
23 | - "/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-03-24-a.xctoolchain/usr/lib/swift/shims/GlobalObjects.h"
24 | - "/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-03-24-a.xctoolchain/usr/lib/swift/shims/FoundationShims.h"
25 | - "/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-03-24-a.xctoolchain/usr/lib/swift/shims/CoreFoundationShims.h"
26 | - "/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-03-24-a.xctoolchain/usr/lib/swift/shims/module.map"
27 | - "/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-03-24-a.xctoolchain/usr/lib/swift/macosx/x86_64/SwiftOnoneSupport.swiftmodule"
28 | - "/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-03-24-a.xctoolchain/usr/lib/swift/macosx/x86_64/Foundation.swiftmodule"
29 | - "/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-03-24-a.xctoolchain/usr/lib/swift/macosx/x86_64/Darwin.swiftmodule"
30 | - "/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-03-24-a.xctoolchain/usr/lib/swift/macosx/x86_64/Dispatch.swiftmodule"
31 | - "/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-03-24-a.xctoolchain/usr/lib/swift/macosx/x86_64/ObjectiveC.swiftmodule"
32 | - "/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-03-24-a.xctoolchain/usr/lib/swift/macosx/x86_64/CoreGraphics.swiftmodule"
33 | - "/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-03-24-a.xctoolchain/usr/lib/swift/macosx/x86_64/IOKit.swiftmodule"
34 | interface-hash: "86d27d5162ef50def2df123343819566"
35 |
--------------------------------------------------------------------------------
/MultilinearMathTests/DispatchPerformaceTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DispatchPerformaceTests.swift
3 | // MultilinearMath
4 | //
5 | // Created by Vincent Herrmann on 22.04.16.
6 | // Copyright © 2016 Vincent Herrmann. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import MultilinearMath
11 |
12 | class DispatchPerformaceTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testNormalizeSimple() {
25 | let values = Array(0..<125000).map({return Float($0)})
26 | let tensor = Tensor(modeSizes: [50, 50, 50], values: values)
27 |
28 | self.measure { //0.046 / 0.01 sec //0.013 / 0.005 sec //0.021 / 0.003 sec
29 | let normalized = normalize(tensor, overModes: [0, 2])
30 | }
31 | }
32 |
33 | func testMode0Normalization() {
34 | let tensor = randomTensor(modeSizes: 5000, 100)
35 |
36 | self.measure { //4.7 / 0.74 sec //1.182 / 0.582 sec //2.0 / 0.128 sec
37 | let normalized = normalize(tensor, overModes: [0])
38 | }
39 |
40 | }
41 |
42 | func testMode1Normalization() {
43 | let tensor = randomTensor(modeSizes: 5000, 100)
44 |
45 | self.measure { //0.29 / 0.085 sec //0.277 / 0.15 sec //0.78 / 0.193 sec
46 | let normalized = normalize(tensor, overModes: [1])
47 | }
48 | }
49 |
50 | func testMode0NormalizationReverse() {
51 | let tensor = randomTensor(modeSizes: 100, 5000)
52 |
53 | self.measure { //4.5 / 0.89 sec //1.4 / 0.713 sec //2.462 / 0.265 sec
54 | let normalized = normalize(tensor, overModes: [0])
55 | }
56 | }
57 |
58 | func testMode1NormalizationReverse() {
59 | let tensor = randomTensor(modeSizes: 100, 5000)
60 |
61 | self.measure { //0.022 / 0.011 sec //0.048 / 0.043 sec //0.34 / 0.048 sec
62 | let normalized = normalize(tensor, overModes: [1])
63 | }
64 | }
65 |
66 | func testMode0Slicing() {
67 | let tensor = ones(10000, 30)
68 |
69 | self.measure { //0.07 / 0.039 sec //0.019 / 0.023 sec //0.032 / 0.002 sec
70 | let slice = tensor[all, 7...7]
71 |
72 | }
73 | }
74 |
75 | func testMode0SlicingRev() {
76 | let tensor = ones(30, 10000)
77 |
78 | self.measure {//0.000 sec //0.000 sec //0.000 sec //0.000 / 0.000 sec
79 | let slice = tensor[all, 7...7]
80 | }
81 | }
82 |
83 | // func testNormalizeDispatched() {
84 | // let values = Array(0..<125000).map({return Float($0)})
85 | // let tensor = Tensor(modeSizes: [50, 50, 50], values: values)
86 | //
87 | // self.measureBlock {
88 | // let normalized = normalizeConcurrent(tensor, overModes: [0, 2])
89 | // }
90 | // }
91 |
92 | }
93 |
--------------------------------------------------------------------------------
/Sources/BoundingProtocols.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BoundingProtocols.swift
3 | // MultilinearMath
4 | //
5 | // Created by Vincent Herrmann on 12.08.16.
6 | // Copyright © 2016 Vincent Herrmann. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public protocol Joinable {
12 | func join(with: Self...) -> Self
13 |
14 | static func join(_ j: [Self]) -> Self
15 | }
16 |
17 | extension CGRect: Joinable {
18 | public func join(with: CGRect...) -> CGRect {
19 | let j = [self] + with
20 | return CGRect.join(j)
21 | }
22 |
23 | public static func join(_ j: [CGRect]) -> CGRect {
24 | let minX = j.map({$0.minX}).min()!
25 | let minY = j.map({$0.minY}).min()!
26 | let maxX = j.map({$0.maxX}).max()!
27 | let maxY = j.map({$0.maxY}).max()!
28 | return CGRect(x: minX, y: minY, width: maxX-minX, height: maxY-minY)
29 | }
30 | }
31 |
32 | public protocol Bounded2D {
33 | var boundingRect: NSRect {get}
34 | }
35 |
36 | public protocol Plotting2D {
37 | var plots: [PlottableIn2D] {get set}
38 | var screenBounds: CGRect {get}
39 | var plottingBounds: CGRect {get set}
40 |
41 | func updatePlotting()
42 | }
43 | public extension Plotting2D {
44 | typealias Transform = (scaleX: CGFloat, scaleY: CGFloat, translateX: CGFloat, translateY: CGFloat)
45 |
46 | var transformFromPlotToScreen: Transform {
47 | get {
48 | return transformParameters(plottingBounds, to: screenBounds)
49 | }
50 | }
51 |
52 | func transformParameters(_ from: NSRect, to: NSRect) -> Transform {
53 | let scaleX = to.width / from.width
54 | let scaleY = to.height / from.height
55 | let translateX = -from.minX * scaleX + to.minX
56 | let translateY = -from.minY * scaleY + to.minY
57 | return (scaleX, scaleY, translateX, translateY)
58 | }
59 |
60 | func convertFromPlotToScreen(_ point: CGPoint) -> CGPoint {
61 | let t = transformParameters(plottingBounds, to: screenBounds)
62 | return CGPoint(x: point.x * t.scaleX + t.translateX, y: point.y * t.scaleY + t.translateY)
63 | }
64 |
65 | func convertFromScreenToPlot(_ point: CGPoint) -> CGPoint {
66 | let t = transformParameters(screenBounds, to: plottingBounds)
67 | return CGPoint(x: point.x * t.scaleX + t.translateX, y: point.y * t.scaleY + t.translateY)
68 | }
69 |
70 | mutating func addPlottable(_ newPlottable: PlottableIn2D) {
71 | newPlottable.fitTo(self)
72 | plots.append(newPlottable)
73 | }
74 |
75 | mutating func setPlottingBounds(_ newBounds: NSRect) {
76 | plottingBounds = newBounds
77 | if(newBounds.width == 0) {
78 | plottingBounds.origin.x += -0.5
79 | plottingBounds.size.width = 1
80 | }
81 | if(newBounds.height == 0) {
82 | plottingBounds.origin.y += -0.5
83 | plottingBounds.size.height = 1
84 | }
85 | }
86 |
87 | func updatePlotting() {
88 | for plot in plots {
89 | plot.fitTo(self)
90 | }
91 | }
92 | }
93 |
94 | public protocol PlottableIn2D {
95 | func draw()
96 | func fitTo(_ plotting: Plotting2D)
97 | }
98 |
--------------------------------------------------------------------------------
/Playgrounds/ComplexWavelets.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | //: Playground - noun: a place where people can play
2 |
3 | import Cocoa
4 | import MultilinearMath
5 |
6 | print("playground started")
7 |
8 | let cA4L2 = calculateComplexWaveletCoefficients(vanishingMoments: 4, delayCoefficients: 3, rootsOutsideUnitCircle: [1, 2])
9 | let cReal = Array(cA4L2.map({$0.real}))
10 | cReal
11 | let cRealW = Array(zip(cReal, Array(0.. Tensor {
12 | guard let data = try? Data(contentsOf: URL(fileURLWithPath: path)) else {
13 | print("could not load file \(path)")
14 | return Tensor(scalar: 0)
15 | }
16 |
17 | var magicNumber: UInt32 = 333
18 | (data as NSData).getBytes(&magicNumber, range: NSRange(location: 0, length: 4))
19 | magicNumber = CFSwapInt32BigToHost(magicNumber)
20 |
21 | var imageCount: UInt32 = 10000
22 | (data as NSData).getBytes(&imageCount, range: NSRange(location: 4, length: 4))
23 | imageCount = CFSwapInt32BigToHost(imageCount)
24 |
25 | var rows: UInt32 = 28
26 | (data as NSData).getBytes(&rows, range: NSRange(location: 8, length: 4))
27 | rows = CFSwapInt32BigToHost(rows)
28 |
29 | var columns: UInt32 = 28
30 | (data as NSData).getBytes(&columns, range: NSRange(location: 12, length: 4))
31 | columns = CFSwapInt32BigToHost(columns)
32 |
33 | print("load \(imageCount) MNIST images of size \(rows) x \(columns)")
34 |
35 | let elementCount = Int(imageCount * rows * columns)
36 | var values = [Float](repeating: 0, count: elementCount)
37 |
38 | let startIndex: Int = 16
39 |
40 | for i in 0..(modeSizes: [Int(imageCount), Int(rows), Int(columns)], values: values)
48 | }
49 |
50 | public func loadMNISTLabelFile(_ path: String) -> [UInt8] {
51 | guard let data = try? Data(contentsOf: URL(fileURLWithPath: path)) else {
52 | print("could not load file \(path)")
53 | return []
54 | }
55 |
56 | var magicNumber: UInt32 = 333
57 | (data as NSData).getBytes(&magicNumber, range: NSRange(location: 0, length: 4))
58 | magicNumber = CFSwapInt32BigToHost(magicNumber)
59 |
60 | var itemCount: UInt32 = 10000
61 | (data as NSData).getBytes(&itemCount, range: NSRange(location: 4, length: 4))
62 | itemCount = CFSwapInt32BigToHost(itemCount)
63 |
64 | print("load \(itemCount) labels")
65 |
66 | let startIndex: Int = 8
67 | let elementCount = Int(itemCount)
68 | var values = [UInt8](repeating: 0, count: elementCount)
69 |
70 | for i in 0.. Tensor {
81 | var oneHotVectors = zeros(labels.count, differentValues.count)
82 | for i in 0.., y: Tensor) -> Tensor {
12 |
13 | let example = TensorIndex.a
14 | let feature = TensorIndex.b
15 |
16 | let exampleCount = x.modeSizes[0]
17 | let featureCount = x.modeSizes[1]
18 |
19 | var samples = Tensor(modeSizes: [exampleCount, featureCount + 1], repeatedValue: 1)
20 | samples[all, 1...featureCount] = x
21 |
22 | // formula: w = (X^T * X)^-1 * X * y
23 | let sampleCovariance = samples[example, feature] * samples[example, .k]
24 | let inverseCovariance = inverse(sampleCovariance, rowMode: 0, columnMode: 1)
25 | let parameters = inverseCovariance[feature, .k] * samples[example, .k] * y[example]
26 |
27 | return parameters
28 | }
29 |
30 | open class LinearRegressionEstimator: ParametricTensorFunction {
31 | open var parameters: [Tensor]
32 | var currentInput: Tensor = zeros()
33 |
34 | fileprivate let example = TensorIndex.a
35 | fileprivate let feature = TensorIndex.b
36 |
37 | public init(featureCount: Int) {
38 | parameters = [zeros(featureCount), zeros()]
39 | parameters[0].indices = [feature]
40 | }
41 |
42 | open func output(_ input: Tensor) -> Tensor {
43 | if(input.modeCount == 1) {
44 | currentInput = Tensor(modeSizes: [1, input.modeSizes[0]], values: input.values)
45 | currentInput.indices = [example, feature]
46 | } else {
47 | currentInput = input[example, feature]
48 | }
49 |
50 | let hypothesis = (currentInput * parameters[0]) + parameters[1]
51 | return hypothesis
52 | }
53 |
54 | open func gradients(_ gradientWrtOutput: Tensor) -> (wrtInput: Tensor, wrtParameters: [Tensor]) {
55 | let parameter0Gradient = gradientWrtOutput * currentInput
56 | let parameter1Gradient = sum(gradientWrtOutput, overModes: [0])
57 | let inputGradient = sum(gradientWrtOutput * parameters[0], overModes: [0])
58 |
59 | return (inputGradient, [parameter0Gradient, parameter1Gradient])
60 | }
61 |
62 | open func updateParameters(_ subtrahends: [Tensor]) {
63 | parameters[0] = parameters[0] - subtrahends[0]
64 | parameters[1] = parameters[1] - subtrahends[1]
65 | }
66 | }
67 |
68 | /// Squared error cost for linear regression
69 | open class LinearRegressionCost: CostFunction {
70 | open var estimator: ParametricTensorFunction
71 | open var regularizers: [ParameterRegularizer?] = [nil, nil]
72 |
73 | public init(featureCount: Int) {
74 | estimator = LinearRegressionEstimator(featureCount: featureCount)
75 | }
76 |
77 | open func costForEstimate(_ estimate: Tensor, target: Tensor) -> Float {
78 | let exampleCount = Float(target.elementCount)
79 |
80 | let distance = estimate - target
81 | let cost = (0.5 / exampleCount) * (distance * distance)
82 |
83 | return cost.values[0]
84 | }
85 |
86 | open func gradientForEstimate(_ estimate: Tensor, target: Tensor) -> Tensor {
87 | if(estimate.indices != target.indices) {
88 | print("abstract indices of estimate and target should be the same!")
89 | }
90 | let exampleCount = Float(target.elementCount)
91 | let gradient = (1/exampleCount) * (estimate - target)
92 |
93 | return gradient
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/MultilinearMath.xcodeproj/xcuserdata/vincentherrmann.xcuserdatad/xcschemes/MultilinearMath.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/MultilinearMath.xcodeproj/xcuserdata/vincentherrmann.xcuserdatad/xcschemes/MultilinearMath 2.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/MultilinearMath.xcodeproj/xcuserdata/vincentherrmann.xcuserdatad/xcschemes/MultilinearMathExample.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/MultilinearMathTests/AccelerateFunctionTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AccelerateFunctionTests.swift
3 | // MultilinearMath
4 | //
5 | // Created by Vincent Herrmann on 13.08.16.
6 | // Copyright © 2016 Vincent Herrmann. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import MultilinearMath
11 |
12 | class AccelerateFunctionTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testExample() {
25 | // This is an example of a functional test case.
26 | // Use XCTAssert and related functions to verify your tests produce the correct results.
27 | }
28 |
29 | func testLinearEquations() {
30 | let matrix: [Float] = [2, 4, -1, 1]
31 | let results: [Float] = [3, 0]
32 | var solution: [Float] = []
33 | matrix.withUnsafeBufferPointer { (a) -> () in
34 | results.withUnsafeBufferPointer({ (b) -> () in
35 | solution = solveLinearEquationSystem(a, factorMatrixSize: MatrixSize(rows: 2, columns: 2), results: b, resultsSize: MatrixSize(rows: 2, columns: 1))
36 | })
37 | }
38 | XCTAssert(solution == [0.5, 0.5], "error in linear equation system solution")
39 | //print("solution: \(solution)")
40 |
41 | let m1: [Float] = [1, 1, 1,
42 | 0, 2, 5,
43 | 2, 5, -1]
44 | let r1: [Float] = [6, -4, 27]
45 | let s1 = solveLinearEquationSystem(m1, factorMatrixSize: MatrixSize(rows: 3, columns: 3), results: r1, resultsSize: MatrixSize(rows: 3, columns: 1))
46 | print("solution: \(s1)")
47 |
48 |
49 | for size in 2..<8 {
50 | print("")
51 | print("size: \(size)")
52 | let m: [Float] = randomTensor(min: -1, max: 1, modeSizes: size, size).values
53 | let r: [Float] = randomTensor(min: -1, max: 1, modeSizes: size).values
54 | solveLinearEquationSystem(m, factorMatrixSize: MatrixSize(rows: size, columns: size), results: r, resultsSize: MatrixSize(rows: size, columns: 1))
55 | }
56 | }
57 |
58 | func testWaveletComputation() {
59 | let db4: [Float] = [0.6830127, 1.1830127, 0.3169873, -0.1830127]
60 | let coefficients = db4
61 | let count = coefficients.count
62 | var factorMatrix = Tensor(modeSizes: [count, count], repeatedValue: 0)
63 | for r in 0..= count) {continue}
68 | factorMatrix[r, index] = coefficients[c]
69 | }
70 | factorMatrix[r, r] += -1
71 | }
72 | factorMatrix[count-1...count-1, all] = ones(4)
73 | print("factor matrix: \(factorMatrix.values)")
74 |
75 | //count = 5
76 | //factorMatrix = randomTensor(min: -1, max: 1, modeSizes: count, count)
77 | let results: [Float] = [Float](repeating: 0, count: count-1) + [1]
78 | var solution: [Float] = []
79 | factorMatrix.values.withUnsafeBufferPointer { (a) -> () in
80 | results.withUnsafeBufferPointer({ (b) -> () in
81 | solution = solveLinearEquationSystem(a, factorMatrixSize: MatrixSize(rows: count, columns: count), results: b, resultsSize: MatrixSize(rows: count, columns: 1))
82 | })
83 | }
84 | print("solution: \(solution)")
85 | }
86 |
87 | func testPerformanceExample() {
88 | // This is an example of a performance test case.
89 | self.measure {
90 | // Put the code you want to measure the time of here.
91 | }
92 | }
93 |
94 | }
95 |
--------------------------------------------------------------------------------
/Sources/Optimization.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Optimization.swift
3 | // MultilinearMath
4 | //
5 | // Created by Vincent Herrmann on 04.05.16.
6 | // Copyright © 2016 Vincent Herrmann. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | //public func batchGradientDescent(objective: GradientOptimizable, input: Tensor, output: Tensor, updateRate: Float, convergenceThreshold: Float = 0.001, maxLoops: Int = 1000) {
12 | //
13 | // var cost = FLT_MAX
14 | //
15 | // for _ in 0.., targets: Tensor, updateRate: Float, convergenceThreshold: Float = 0.00001, maxLoops: Int = Int.max, minibatchSize: Int = 16, validationCallback: (_ currentEpoch: Int, _ currentEstimator: ParametricTensorFunction) -> (Bool) = {(epoch, _) in print("epoch \(epoch)"); return false}) {
29 |
30 | var cost = FLT_MAX
31 | var epoch = 0
32 | var currentBatch = inputs
33 | var currentBatchTargets = targets
34 | var currentIndex = 0
35 | var convergenceCounter = 0
36 |
37 | print("stochastic gradient descent")
38 |
39 | for _ in 0..
42 | var minibatchTargets: Tensor
43 | if(currentIndex + minibatchSize < currentBatch.modeSizes[0]) {
44 | let minibatchRange = CountableRange(start: currentIndex, distance: minibatchSize)
45 |
46 | minibatch = currentBatch[minibatchRange, all]
47 | minibatchTargets = currentBatchTargets[minibatchRange, all]
48 |
49 | currentIndex += minibatchSize
50 | } else {
51 | //call validiation callback, if it returns true, break the optimization loop
52 | if(validationCallback(epoch, objective.estimator)) {
53 | break
54 | }
55 |
56 | let minibatchRange = currentIndex..= 3) {
85 | print("converged!")
86 | break
87 | }
88 | }
89 | cost = newCost
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # multilinear-math
2 | Swift library for multidimensional data, tensor operations and machine learning on OS X. For additional comments and documentation, please take a look at the [Wiki](https://github.com/vincentherrmann/multilinear-math/wiki).
3 |
4 | Already implemented:
5 | - Swift wrappers of many important functions from the Accelerate framework and LAPACK (vector summation, addition, substraction, matrix and elementwise multiplication, division, matrix inverse, pseudo inverse, eigendecomposition, singular value decomposition...)
6 | - `MultidimensionData` protocol for elegant handling of multidimensional data of any kind
7 | - Clear, compact and powerful syntax for mathematical operations on tensors
8 | - Principal component analysis
9 | - Multilinear subspace learning algorithms for dimensionality reduction
10 | - Linear and logistic regression
11 | - Stochastic gradient descent
12 | - Feedforward neural networks
13 | - Sigmoid, ReLU, Softplus activation functions
14 | - Easy regularizations
15 |
16 | ## Tensor reading, writing, slicing
17 | Create data tensor:
18 | ```swift
19 | var a = Tensor(modeSizes: [3, 3, 3], repeatedValue: 0)
20 | ```
21 |
22 | Read and write single values:
23 | ```swift
24 | let b: Float = a[1, 2, 0]
25 | a[2, 0, 1] = 3.14
26 | ```
27 |
28 | Read and write a tensor slice
29 | ```swift
30 | let c: Tensor = a[1..<3, all, [0]]
31 | a[1...1, [0, 2], all] = Tensor(modeSizes: [2, 3], values: [1, 2, 3, 4, 5, 6])
32 | ```
33 | *modes of size 1 will be trimmed*
34 |
35 | ## Einstein notation
36 | Modes with same symbolic index will be summed over. Simple matrix multiplication:
37 | ```swift
38 | var m = Tensor(modeSizes: [4, 6], repeatedValue: 1)
39 | var n = Tensor(modeSizes: [6, 5], repeatedValue: 2)
40 | let matrixProduct = m[.i, .j] * n[.j, .k]
41 | ```
42 | Geodesic deviation:
43 | ```swift
44 | var tangentVector = Tensor(modeSizes: [4], values: [0.3, 1.7, 0.2, 0.5])
45 | tangentVector.isCartesian = false
46 |
47 | var deviationVector = Tensor(modeSizes: [4], values: [0.1, 0.9, 0.4, 1.2])
48 | deviationVector.isCartesian = false
49 |
50 | var riemannianTensor = Tensor(diagonalWithModeSizes: [4, 4, 4, 4])
51 | riemannianTensor.isCartesian = false
52 | riemannianTensor.variances = [.contravariant, .covariant, .covariant, .covariant]
53 |
54 | let relativeAcceleration = riemannianTensor[.μ, .ν, .ρ, .σ] * tangentVector[.ν] * tangentVector[.ρ] * deviationTensor[.σ]
55 | ```
56 |
57 | ## Neural networks
58 | Setting up and training a simple feedforward neural net:
59 | ```swift
60 | var estimator = NeuralNet(layerSizes: [28*28, 40, 10])
61 | estimator.layers[0].activationFunction = ReLU(secondarySlope: 0.01)
62 | estimator.layers[1].activationFunction = ReLU(secondarySlope: 0.01)
63 |
64 | var neuralNetCost = SquaredErrorCost(forEstimator: estimator)
65 |
66 | stochasticGradientDescent(neuralNetCost, inputs: trainingData[.a, .b], targets: trainingLabels[.a, .c], updateRate: 0.1, minibatchSize: 50, validationCallback: ({ (epoch, estimator) -> (Bool) in
67 | if(epoch >= 30) {return true}
68 | else {return false}
69 | }))
70 | ```
71 | [documentation](https://github.com/vincentherrmann/multilinear-math/wiki/Neural-Networks)
72 |
73 | ## Multilinear subspace learning
74 | Extended PCA algorithms to work with tensors with arbitrary mode count
75 | - [multilinear principal component analysis (MPCA)](https://github.com/vincentherrmann/multilinear-math/wiki/Subspace-Learning)
76 | - [uncorrelated multilinear principal component analysis (UMPCA)](https://github.com/vincentherrmann/multilinear-math/wiki/Subspace-Learning)
77 | *(Lu, Plataniotis, Venetsanopoulos)*
78 |
79 | ## Installation
80 | To use this framework in an OSX XCode project:
81 | - clone this repository
82 | - open your project in XCode
83 | - drag and drop MultilinearMath.xcodeproj into the project navigator of your project
84 | - select the .xcodeproj file of your project in the navigator
85 | - go to the "General" tab and add MultilinearMath.framework to the Linked Frameworks and Libraries
86 | - go to the "Build Settings" tab and set "Embedded Content Contains Swift Code" to YES
87 | - import MultilinearMath in your Swift files
88 |
89 | If possible, whole module optimization should be used for very significant performance gains.
90 |
91 |
--------------------------------------------------------------------------------
/Playgrounds/WaveletPacketTransform.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | //: Playground - noun: a place where people can play
2 |
3 | import Cocoa
4 | import MultilinearMath
5 |
6 | print("playground started")
7 |
8 | let cReal: [Float] = [-0.00252085552, 0.0188991688, 0.0510309711, -0.0490589067, 0.0589671507, 0.79271543, 1.0953089, 0.32142213, -0.227000564, -0.0872127786, 0.0242141522, 0.0032346386]
9 | //let cReal: [Float] = [0.6830127, 1.1830127, 0.3169873, -0.1830127]
10 |
11 | let wavelet = Wavelet(h0: cReal, f0: cReal.reversed())
12 |
13 | let xArray = Array(0..<50).map({Float.pi * Float($0) / 50})
14 |
15 | var filter = FIRFilter(coefficients: wavelet.analysisFilter(for: 2))
16 | QuickArrayPlot(array: filter.coefficients)
17 | let ft2 = filter.frequencyResponse().response.map({$0.absoluteValue})
18 | QuickLinesPlot(x: xArray, y: ft2)
19 |
20 | filter = FIRFilter(coefficients: wavelet.analysisFilter(for: 3))
21 | QuickArrayPlot(array: filter.coefficients)
22 | let ft3 = filter.frequencyResponse().response.map({$0.absoluteValue})
23 | QuickLinesPlot(x: xArray, y: ft3)
24 |
25 | filter = FIRFilter(coefficients: wavelet.analysisFilter(for: 4))
26 | QuickArrayPlot(array: filter.coefficients)
27 | let ft4 = filter.frequencyResponse().response.map({$0.absoluteValue})
28 | QuickLinesPlot(x: xArray, y: ft4)
29 |
30 | filter = FIRFilter(coefficients: wavelet.analysisFilter(for: 5))
31 | QuickArrayPlot(array: filter.coefficients)
32 | let ft5 = filter.frequencyResponse().response.map({$0.absoluteValue})
33 | QuickLinesPlot(x: xArray, y: ft5)
34 |
35 | filter = FIRFilter(coefficients: wavelet.analysisFilter(for: 6))
36 | QuickArrayPlot(array: filter.coefficients)
37 | let ft6 = filter.frequencyResponse().response.map({$0.absoluteValue})
38 | QuickLinesPlot(x: xArray, y: ft6)
39 |
40 | filter = FIRFilter(coefficients: wavelet.analysisFilter(for: 7))
41 | QuickArrayPlot(array: filter.coefficients)
42 | let ft7 = filter.frequencyResponse().response.map({$0.absoluteValue})
43 | QuickLinesPlot(x: xArray, y: ft7)
44 |
45 | filter = FIRFilter(coefficients: wavelet.analysisFilter(for: 8))
46 | QuickArrayPlot(array: filter.coefficients)
47 | let ft8 = filter.frequencyResponse().response.map({$0.absoluteValue})
48 | QuickLinesPlot(x: xArray, y: ft8)
49 | filter = FIRFilter(coefficients: wavelet.analysisFilter(for: 9))
50 | QuickArrayPlot(array: filter.coefficients)
51 | let ft9 = filter.frequencyResponse().response.map({$0.absoluteValue})
52 | QuickLinesPlot(x: xArray, y: ft9)
53 |
54 | filter = FIRFilter(coefficients: wavelet.analysisFilter(for: 10))
55 | QuickArrayPlot(array: filter.coefficients)
56 | let ft10 = filter.frequencyResponse().response.map({$0.absoluteValue})
57 | QuickLinesPlot(x: xArray, y: ft10)
58 |
59 | filter = FIRFilter(coefficients: wavelet.analysisFilter(for: 11))
60 | QuickArrayPlot(array: filter.coefficients)
61 | let ft11 = filter.frequencyResponse().response.map({$0.absoluteValue})
62 | QuickLinesPlot(x: xArray, y: ft11)
63 |
64 | filter = FIRFilter(coefficients: wavelet.analysisFilter(for: 12))
65 | QuickArrayPlot(array: filter.coefficients)
66 | let ft12 = filter.frequencyResponse().response.map({$0.absoluteValue})
67 | QuickLinesPlot(x: xArray, y: ft12)
68 |
69 | filter = FIRFilter(coefficients: wavelet.analysisFilter(for: 13))
70 | QuickArrayPlot(array: filter.coefficients)
71 | let ft13 = filter.frequencyResponse().response.map({$0.absoluteValue})
72 | QuickLinesPlot(x: xArray, y: ft13)
73 |
74 | filter = FIRFilter(coefficients: wavelet.analysisFilter(for: 14))
75 | QuickArrayPlot(array: filter.coefficients)
76 | let ft14 = filter.frequencyResponse().response.map({$0.absoluteValue})
77 | QuickLinesPlot(x: xArray, y: ft14)
78 |
79 | filter = FIRFilter(coefficients: wavelet.analysisFilter(for: 15))
80 | QuickArrayPlot(array: filter.coefficients)
81 | let ft15 = filter.frequencyResponse().response.map({$0.absoluteValue})
82 | QuickLinesPlot(x: xArray, y: ft15)
83 |
84 | filter = FIRFilter(coefficients: wavelet.analysisFilter(for: 16))
85 | QuickArrayPlot(array: filter.coefficients)
86 | let ft16 = filter.frequencyResponse().response.map({$0.absoluteValue})
87 | QuickLinesPlot(x: xArray, y: ft16)
88 |
89 | filter = FIRFilter(coefficients: wavelet.analysisFilter(for: 24))
90 | QuickArrayPlot(array: filter.coefficients)
91 | let ft24 = filter.frequencyResponse().response.map({$0.absoluteValue})
92 | QuickLinesPlot(x: xArray, y: ft24)
93 |
94 | filter = FIRFilter(coefficients: wavelet.analysisFilter(for: 56))
95 | QuickArrayPlot(array: filter.coefficients)
96 | let ft56 = filter.frequencyResponse().response.map({$0.absoluteValue})
97 | QuickLinesPlot(x: xArray, y: ft56)
98 |
--------------------------------------------------------------------------------
/Sources/WaveletPlots.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WaveletPlots.swift
3 | // MultilinearMath
4 | //
5 | // Created by Vincent Herrmann on 07.11.16.
6 | // Copyright © 2016 Vincent Herrmann. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | public struct FastWaveletPlot: CustomPlaygroundQuickLookable {
12 | public var waveletView: WaveletView
13 |
14 | public var customPlaygroundQuickLook: PlaygroundQuickLook {
15 | get {
16 | return PlaygroundQuickLook.view(waveletView)
17 | }
18 | }
19 |
20 | public init(packets: [WaveletPacket]) {
21 | waveletView = WaveletView(frame: NSRect(x: 0, y: 0, width: 300, height: 200))
22 | var bounds: CGRect? = nil
23 | for i in 0.. maxValue {maxValue = CGFloat(m)}
69 | }
70 | }
71 | }
72 |
73 | super.updatePlotting()
74 | }
75 | }
76 |
77 | public class WaveletPacketPlot: PlottableIn2D {
78 | public var packet: WaveletPacket
79 | var tiles: [CGRect] = []
80 | var maxValue: CGFloat = 1
81 | public var plotBounds: CGRect {
82 | get {
83 | let yMinP = CGFloat(packet.position) / CGFloat(packet.length)
84 | let height = 1 / CGFloat(packet.length)
85 | let width = CGFloat(packet.length * packet.values.count)
86 | let bounds = CGRect(x: 0, y: yMinP, width: width, height: height)
87 | return bounds
88 | }
89 | }
90 |
91 | public init(packet: WaveletPacket) {
92 | self.packet = packet
93 | }
94 |
95 | public func draw() {
96 | for i in 0..]
13 | var currentInput: Tensor = zeros()
14 | var currentPreactivations: Tensor = zeros()
15 |
16 | fileprivate let example = TensorIndex.a
17 | fileprivate let feature = TensorIndex.b
18 |
19 |
20 | public init(featureCount: Int) {
21 | parameters = [zeros(featureCount), zeros()]
22 | parameters[0].indices = [feature]
23 | }
24 |
25 | open func output(_ input: Tensor) -> Tensor {
26 | if(input.modeCount == 1) {
27 | currentInput = Tensor(modeSizes: [1, input.modeSizes[0]], values: input.values)
28 | currentInput.indices = [example, feature]
29 | } else {
30 | currentInput = input[example, feature]
31 | }
32 |
33 | currentPreactivations = (currentInput * parameters[0]) + parameters[1]
34 | let currentHypothesis = Sigmoid().output(currentPreactivations)
35 | return currentHypothesis
36 | }
37 |
38 | open func gradients(_ gradientWrtOutput: Tensor) -> (wrtInput: Tensor, wrtParameters: [Tensor]) {
39 | let sigmoidGradient = Sigmoid().derivative(currentPreactivations)
40 | let preactivationGradient = sigmoidGradient °* gradientWrtOutput
41 | let parameter0Gradient = preactivationGradient * currentInput
42 | let parameter1Gradient = sum(preactivationGradient, overModes: [0])
43 | let inputGradient = sum(preactivationGradient * parameters[0], overModes: [0])
44 |
45 | return (inputGradient, [parameter0Gradient, parameter1Gradient])
46 | }
47 |
48 | open func updateParameters(_ subtrahends: [Tensor]) {
49 | parameters[0] = parameters[0] - subtrahends[0]
50 | parameters[1] = parameters[1] - subtrahends[1]
51 | }
52 | }
53 |
54 | /// Negative log likelihood cost for logistic regression
55 | open class LogisticRegressionCost: CostFunction {
56 | open var estimator: ParametricTensorFunction
57 | open var regularizers: [ParameterRegularizer?] = [nil, nil]
58 |
59 | public init(featureCount: Int) {
60 | estimator = LogisticRegressionEstimator(featureCount: featureCount)
61 | }
62 |
63 | open func costForEstimate(_ estimate: Tensor, target: Tensor) -> Float {
64 | let exampleCount = Float(target.elementCount)
65 |
66 | let t1 = -target °* log(estimate)
67 | let t2 = (1-target) °* log(1-estimate)
68 | let cost = vectorSummation((t1-t2).values) / exampleCount
69 |
70 | return cost
71 | }
72 |
73 | open func gradientForEstimate(_ estimate: Tensor, target: Tensor) -> Tensor {
74 | if(estimate.indices != target.indices) {
75 | print("abstract indices of estimate and target should be the same!")
76 | }
77 |
78 | let g1 = target °* (1/estimate)
79 | let g2 = (1-target) °* (1 / (1-estimate))
80 | let gradient = -(g1 - g2)
81 |
82 | return gradient
83 | }
84 | }
85 |
86 | //public func oneVsAllClassification(x x: Tensor, y: Tensor, classCount: Int, regularize: Float = 0) -> Tensor {
87 | //
88 | // let exampleCount = x.modeSizes[0]
89 | // let featureCount = x.modeSizes[1]
90 | //
91 | // var yClasses = [zeros(classCount, exampleCount)]
92 | // for c in 0..(modeSizes: [exampleCount], values: y.values.map({Float($0 == Float(c))}))
94 | // }
95 | //
96 | // var outputData = [zeros(classCount, featureCount+1)]
97 | //
98 | // combine(x, forOuterModes: [], with: yClasses[0], forOuterModes: [0], outputData: &outputData,
99 | // calculate: ({ (indexA, indexB, outerIndex, sourceA, sourceB) -> [Tensor] in
100 | // let result = logisticRegression(x: sourceA, y: sourceB[slice: indexB])
101 | // return [result]
102 | // }),
103 | // writeOutput: ({ (indexA, indexB, outerIndex, inputData, outputData) in
104 | // outputData[0][slice: outerIndex + [all]] = inputData[0]
105 | // }))
106 | //
107 | // return (outputData[0])
108 | //}
109 |
--------------------------------------------------------------------------------
/Sources/TensorSyntacticOperators.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TensorSyntacticOperators.swift
3 | // MultilinearMath
4 | //
5 | // Created by Vincent Herrmann on 23.04.16.
6 | // Copyright © 2016 Vincent Herrmann. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | // MARK: - Scalar-Tensor functions
12 | /// Negative of a tensor
13 | public prefix func -(tensor: Tensor) -> Tensor {
14 | let negative = Tensor(withPropertiesOf: tensor, values: vectorNegation(tensor.values))
15 | return negative
16 | }
17 |
18 | /// add a scalar to every element of a tensor
19 | public func +(lhs: Tensor, rhs: Float) -> Tensor {
20 | let sum = Tensor.init(withPropertiesOf: lhs, values: vectorAddition(vector: lhs.values, add: rhs))
21 | return sum
22 | }
23 | /// add a scalar to every element of a tensor
24 | public func +(lhs: Float, rhs: Tensor) -> Tensor {
25 | return rhs+lhs
26 | }
27 |
28 | /// substract a scalar from every element of a tensor
29 | public func -(lhs: Tensor, rhs: Float) -> Tensor {
30 | let diff = Tensor(withPropertiesOf: lhs, values: vectorAddition(vector: lhs.values, add: -rhs))
31 | return diff
32 | }
33 |
34 | /// substract every element of a tensor from a scalar
35 | public func -(lhs: Float, rhs: Tensor) -> Tensor {
36 | return lhs + (-rhs)
37 | }
38 |
39 | /// multiply every element of a tensor with a scalar
40 | public func *(lhs: Tensor, rhs: Float) -> Tensor {
41 | let product = Tensor.init(withPropertiesOf: lhs, values: vectorMultiplication(lhs.values, factor: rhs))
42 | return product
43 | }
44 | /// multiply every element of a tensor with a scalar
45 | public func *(lhs: Float, rhs: Tensor) -> Tensor {
46 | return rhs*lhs
47 | }
48 |
49 | // MARK: - Tensor-Tensor functions
50 | public func +(lhs: Tensor, rhs: Tensor) -> Tensor {
51 |
52 | let commonIndices = lhs.commonIndicesWith(rhs)
53 | let commonModesLhs = commonIndices.map({$0.modeA})
54 | let outerModesLhs = lhs.modeArray.removeValues(commonModesLhs)
55 | let commonModesRhs = commonIndices.map({$0.modeB})
56 | let outerModesRhs = rhs.modeArray.removeValues(commonModesRhs)
57 |
58 | let sum = add(a: lhs, commonModesA: commonModesLhs, outerModesA: outerModesLhs, b: rhs, commonModesB: commonModesRhs, outerModesB: outerModesRhs)
59 |
60 | return sum
61 | }
62 |
63 | public func -(lhs: Tensor, rhs: Tensor) -> Tensor {
64 |
65 | let commonIndices = lhs.commonIndicesWith(rhs)
66 | let commonModesLhs = commonIndices.map({$0.modeA})
67 | let outerModesLhs = lhs.modeArray.removeValues(commonModesLhs)
68 | let commonModesRhs = commonIndices.map({$0.modeB})
69 | let outerModesRhs = rhs.modeArray.removeValues(commonModesRhs)
70 |
71 | let difference = substract(a: lhs, commonModesA: commonModesLhs, outerModesA: outerModesLhs, b: rhs, commonModesB: commonModesRhs, outerModesB: outerModesRhs)
72 |
73 | return difference
74 | }
75 |
76 | infix operator °*
77 | public func °*(lhs: Tensor, rhs: Tensor) -> Tensor {
78 |
79 | let commonIndices = lhs.commonIndicesWith(rhs)
80 | let commonModesLhs = commonIndices.map({$0.modeA})
81 | let outerModesLhs = lhs.modeArray.removeValues(commonModesLhs)
82 | let commonModesRhs = commonIndices.map({$0.modeB})
83 | let outerModesRhs = rhs.modeArray.removeValues(commonModesRhs)
84 |
85 | let product = multiplyElementwise(a: lhs, commonModesA: commonModesLhs, outerModesA: outerModesLhs, b: rhs, commonModesB: commonModesRhs, outerModesB: outerModesRhs)
86 |
87 | return product
88 | }
89 |
90 | infix operator °/
91 | public func °/(lhs: Tensor, rhs: Tensor) -> Tensor {
92 |
93 | let commonIndices = lhs.commonIndicesWith(rhs)
94 | let commonModesLhs = commonIndices.map({$0.modeA})
95 | let outerModesLhs = lhs.modeArray.removeValues(commonModesLhs)
96 | let commonModesRhs = commonIndices.map({$0.modeB})
97 | let outerModesRhs = rhs.modeArray.removeValues(commonModesRhs)
98 |
99 | let quotient = divide(a: lhs, commonModesA: commonModesLhs, outerModesA: outerModesLhs, b: rhs, commonModesB: commonModesRhs, outerModesB: outerModesRhs)
100 |
101 | return quotient
102 | }
103 |
104 | /// divide a scalar by every element of a tensor
105 | public func /(lhs: Float, rhs: Tensor) -> Tensor {
106 | let quotient = Tensor.init(withPropertiesOf: rhs, values: vectorDivision(numerator: lhs, vector: rhs.values))
107 | return quotient
108 | }
109 |
--------------------------------------------------------------------------------
/Sources/DaubechiesWavelets.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DaubechiesWavelets.swift
3 | // MultilinearMath
4 | //
5 | // Created by Vincent Herrmann on 12.10.16.
6 | // Copyright © 2016 Vincent Herrmann. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public class DaubechiesWavelet: Wavelet {
12 | public init(vanishingMoments: Int) {
13 | let c = calculateDaubechiesCoefficients(vanishingMoments: vanishingMoments)
14 | super.init(h0: c, f0: c.reversed())
15 | }
16 | }
17 |
18 | public func calculateDaubechiesCoefficients(vanishingMoments: Int) -> [Float] {
19 |
20 | //create Q polynomial
21 | var summedExpansion: [PolynomialTerm] = [(1 + 0*i, 0)]
22 | let qBase: [PolynomialTerm] = [(0.5 + 0*i, 0), (-0.25 + 0*i, 1), (-0.25 + 0*i, -1)]
23 |
24 | for n in 1.. 1 {
52 | roots.append(1 / root)
53 | } else {
54 | roots.append(root)
55 | }
56 | }
57 |
58 | if roots.count >= vanishingMoments-1 {
59 | break
60 | }
61 | }
62 |
63 | //create H0 polynomial
64 | var h0: [PolynomialTerm] = [(2 + 0*i, 0)]
65 |
66 | for _ in 0.. [PolynomialTerm] {
95 |
96 | var expansion: [PolynomialTerm] = []
97 |
98 | for term1 in factor1 {
99 | for term2 in factor2 {
100 | let coeff = term1.coefficient * term2.coefficient
101 | let pow = term1.power + term2.power
102 |
103 | if let i = expansion.map({$0.power}).index(where: {$0 == pow}) {
104 | expansion[i] = (expansion[i].coefficient + coeff, pow)
105 | } else {
106 | expansion.append((term1.coefficient * term2.coefficient, term1.power + term2.power))
107 | }
108 | }
109 | }
110 |
111 | expansion.sort(by: {$0.power < $1.power})
112 |
113 | return expansion
114 | }
115 |
116 | public func binomialCoefficient(_ a: Int, choose b: Int) -> Int {
117 | let num = Array(1...a).reduce(1, {$0*$1})
118 | let f1 = Array(1...b).reduce(1, {$0*$1})
119 | let f2 = Array(1...(a-b)).reduce(1, {$0*$1})
120 | return num/(f1*f2)
121 | }
122 |
123 | public struct ComplexNewtonApproximator {
124 | public var polynomial: ComplexPolynomial
125 | public var threshold: Float = 0.00000001
126 | public var maxIterations: Int = 50
127 |
128 | public init(polynomial: ComplexPolynomial) {
129 | self.polynomial = polynomial
130 | }
131 |
132 | public func findRoot(from: ComplexNumber) -> ComplexNumber? {
133 | var currentPosition = from
134 | var currentValue = polynomial.valueFor(z: currentPosition)
135 |
136 | for _ in 0.. Bool {
55 | if (lhs.real == rhs.real && lhs.imaginary == rhs.imaginary) {
56 | return true
57 | } else {
58 | return false
59 | }
60 | }
61 |
62 | static public func abs(_ x: ComplexNumber) -> ComplexNumber {
63 | return ComplexNumber(real: x.absoluteValue, imaginary: 0)
64 | }
65 | }
66 |
67 | public func +(lhs: ComplexNumber, rhs: ComplexNumber) -> ComplexNumber {
68 | return ComplexNumber(real: lhs.real + rhs.real, imaginary: lhs.imaginary + rhs.imaginary)
69 | }
70 | public func +(lhs: ComplexNumber, rhs: Float) -> ComplexNumber {
71 | return ComplexNumber(real: lhs.real + rhs, imaginary: lhs.imaginary)
72 | }
73 | public func +(lhs: Float, rhs: ComplexNumber) -> ComplexNumber {
74 | return ComplexNumber(real: lhs + rhs.real, imaginary: rhs.imaginary)
75 | }
76 |
77 | public prefix func -(a: ComplexNumber) -> ComplexNumber {
78 | return ComplexNumber(real: -a.real, imaginary: -a.imaginary)
79 | }
80 | public func -(lhs: ComplexNumber, rhs: ComplexNumber) -> ComplexNumber {
81 | return ComplexNumber(real: lhs.real - rhs.real, imaginary: lhs.imaginary - rhs.imaginary)
82 | }
83 | public func -(lhs: ComplexNumber, rhs: Float) -> ComplexNumber {
84 | return ComplexNumber(real: lhs.real - rhs, imaginary: lhs.imaginary)
85 | }
86 | public func -(lhs: Float, rhs: ComplexNumber) -> ComplexNumber {
87 | return ComplexNumber(real: lhs - rhs.real, imaginary: -rhs.imaginary)
88 | }
89 |
90 | public func *(lhs: ComplexNumber, rhs: ComplexNumber) -> ComplexNumber {
91 | let r = lhs.real * rhs.real - lhs.imaginary * rhs.imaginary
92 | let i = lhs.imaginary * rhs.real + lhs.real * rhs.imaginary
93 | return ComplexNumber(real: r, imaginary: i)
94 | }
95 | public func *(lhs: ComplexNumber, rhs: Float) -> ComplexNumber {
96 | return ComplexNumber(real: lhs.real * rhs, imaginary: lhs.imaginary * rhs)
97 | }
98 | public func *(lhs: Float, rhs: ComplexNumber) -> ComplexNumber {
99 | return ComplexNumber(real: lhs * rhs.real, imaginary: lhs * rhs.imaginary)
100 | }
101 |
102 | public func /(lhs: ComplexNumber, rhs: ComplexNumber) -> ComplexNumber {
103 | let denominator = rhs.real * rhs.real + rhs.imaginary * rhs.imaginary
104 | let r = (lhs.real * rhs.real + lhs.imaginary * rhs.imaginary) / denominator
105 | let i = (lhs.imaginary * rhs.real - lhs.real * rhs.imaginary) / denominator
106 | return ComplexNumber(real: r, imaginary: i)
107 | }
108 | public func /(lhs: ComplexNumber, rhs: Float) -> ComplexNumber {
109 | return ComplexNumber(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs)
110 | }
111 | public func /(lhs: Float, rhs: ComplexNumber) -> ComplexNumber {
112 | return ComplexNumber(real: lhs, imaginary: 0) / rhs
113 | }
114 |
115 | public func pow(_ z: ComplexNumber, n: Int) -> ComplexNumber {
116 | var r = 1 + i*0
117 | if n == 0 {
118 | return r
119 | } else if n > 0 {
120 | for _ in 0.. ComplexNumber {
148 | var currentZ: ComplexNumber = ComplexNumber(real: 1, imaginary: 0)
149 | var currentResult: ComplexNumber = ComplexNumber(real: 0, imaginary: 0)
150 |
151 | for c in coefficients {
152 | let s = c * currentZ
153 | currentResult = currentResult + s
154 | currentZ = currentZ * z
155 | }
156 |
157 | return currentResult
158 | }
159 | }
160 |
161 |
162 |
163 |
164 |
165 |
--------------------------------------------------------------------------------
/Playgrounds/WaveletPlayground.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | //: Playground - noun: a place where people can play
2 |
3 | import Cocoa
4 | import MultilinearMath
5 |
6 | let db2: [Float] = [1, 1]
7 | let db4: [Float] = [0.6830127, 1.1830127, 0.3169873, -0.1830127]
8 | let db4w: [Float] = [0.6830127, -1.1830127, 0.3169873, 0.1830127]
9 | let db6: [Float] = [0.3326705529509569, 0.8068915093133388, 0.4598775021193313, -0.13501102001039084, -0.08544127388224149, 0.035226291882100656].map({$0 * pow(2, 0.5)})
10 | let db8: [Float] = [0.23037781330885523, 0.7148465705525415, 0.6308807679295904, -0.02798376941698385, -0.18703481171888114, 0.030841381835986965, 0.032883011666982945, -0.010597401784997278].map({$0 * pow(2, 0.5)})
11 |
12 | //QuickArrayPlot(array: db2)
13 | let db2Wavelet = scalingFunction(from: db2, levels: 6)
14 | QuickArrayPlot(array: db2Wavelet)
15 |
16 | QuickArrayPlot(array: db4)
17 | let db4Wavelet = scalingFunction(from: db4, levels: 6)
18 | //let db4WaveletP = QuickArrayPlot(array: db4Wavelet)
19 | let db4WaveletY = Array(0.. [ComplexNumber] {
12 |
13 | //create S polynomial
14 | var sPolynomial: [PolynomialTerm] = [(1 + 0*i, 0)]
15 | let sBase: [PolynomialTerm] = [(1 + 0*i, 1), (2 + 0*i, 0), (1 + 0*i, -1)]
16 |
17 | for _ in 0..(modeSizes: [fmSize, fmSize], repeatedValue: 0)
35 | var results = [Float](repeating: 0, count: fmSize)
36 | for r in 0..= sPolynomial.count) {continue}
41 | factorMatrix[r, c] = sPolynomial[index].coefficient.real
42 | }
43 | if n == 0 {
44 | results[r] = 2
45 | }
46 | }
47 | print("factor matrix: \(factorMatrix.values)")
48 | print("results: \(results)")
49 | let rCoefficients = solveLinearEquationSystem(factorMatrix.values, factorMatrixSize: MatrixSize(rows: fmSize, columns: fmSize), results: results, resultsSize: MatrixSize(rows: fmSize, columns: 1))
50 | print("r: \(rCoefficients)")
51 |
52 | let qPolynomial = ComplexPolynomial(coefficients: rCoefficients.map({$0 + i*0}))
53 |
54 | //find roots
55 | let newton = ComplexNewtonApproximator(polynomial: qPolynomial)
56 | var roots: [ComplexNumber] = []
57 |
58 | for s in 0..<(10*vanishingMoments) {
59 | let start = cos(2.6 * Float(s)) + sin(2.6 * Float(s))*i
60 | if let root = newton.findRoot(from: start) {
61 | if roots.contains(where: {($0 - root).absoluteValue < 0.001}) {
62 | continue
63 | } else if root.absoluteValue > 1 {
64 | roots.append(1 / root)
65 | } else {
66 | roots.append(root)
67 | }
68 | }
69 |
70 | if roots.count >= vanishingMoments + delayCoefficients - 2 {
71 | break
72 | }
73 | }
74 |
75 | roots.sort(by: {$0.0.absoluteValue < $0.1.absoluteValue})
76 | for r in rootsOutsideUnitCircle {
77 | if r >= roots.count {continue}
78 | roots[r] = 1 / roots[r]
79 | }
80 |
81 |
82 | print("roots: \(roots)")
83 |
84 | //create H0 polynomial
85 | var h0: [PolynomialTerm] = [(2 + 0*i, 0)]
86 |
87 | for _ in 0.. [Float] {
114 |
115 | if(count == 0) {
116 | return [1]
117 | }
118 |
119 | var currentD: Float = 1
120 | var d: [Float] = [currentD]
121 |
122 | let L = Float(count - 1)
123 |
124 | for n in 0.. ComplexNumber {
138 | // let base = cos(frequency) + i*sin(frequency)
139 | // var e = 1 / base
140 | var r = 0 + i*0
141 |
142 | for n in 0.. (abs: [Float], arg: [Float], xArray: [Float]) {
152 | // let xDist = Float(x.max()! - x.min()!)
153 | // let count = Float(filter.count - 1)
154 | // let m = 0.5*log2(count / xDist) * Float.pi
155 | let m = 2 * x.max()! * Float.pi
156 | // print("fourier m: \(m)")
157 | let omegas = (0.. [Float] {
12 | var wavelet = calculateIntegerWaveletValues(coefficients)
13 | for _ in 0.. [Float] {
20 | var approx: [Float] = [1]
21 | for _ in 0.. [Float] {
28 | print("calculate wavelet function with \(scalingFunction.count) values")
29 | let distance = (scalingFunction.count-1) / (coefficients.count - 1)
30 | print("distance: \(distance)")
31 | var waveletFunction = [Float](repeating: 0, count: scalingFunction.count)
32 |
33 | for t in 0..= scalingFunction.count) {continue}
38 | currentValue += scalingFunction[index] * coefficients[k]
39 | }
40 | waveletFunction[t] = currentValue
41 | }
42 |
43 | return waveletFunction
44 | }
45 |
46 | /// calculate the values of the wavelet function on the integer position from the filter coefficients. This is done by solving a system of linear equations constructed from the dilation equation
47 | public func calculateIntegerWaveletValues(_ coefficients: [Float]) -> [Float] {
48 | let count = coefficients.count
49 |
50 | //calculate factor matrix (left side of the equation system)
51 | //example: db4 coeffients a0, a1, a2, a3
52 | // a0-1 0 0 0 = 0
53 | // a2 a1-1 a0 0 = 0
54 | // 0 a3 a2-1 a1 = 0
55 | // 0 0 0 a3-1 = 0
56 | // 1 1 1 1 = 1 //this last equation is added to each row to get an unambiguous solution
57 | var factorMatrix = Tensor(modeSizes: [count, count], repeatedValue: 0)
58 | for r in 0..= count) {continue}
63 | factorMatrix[r, index] = coefficients[c]
64 | }
65 | factorMatrix[r, r] += -1
66 | }
67 | factorMatrix = factorMatrix + 1
68 | let results = [Float](repeating: 1, count: count-1) + [1]
69 |
70 | print("count: \(count)")
71 | print("factor matrix: \(factorMatrix.values)")
72 | print("results: \(results)")
73 | let solution = solveLinearEquationSystem(factorMatrix.values, factorMatrixSize: MatrixSize(rows: count, columns: count), results: results, resultsSize: MatrixSize(rows: count, columns: 1))
74 |
75 | let testResults = matrixMultiplication(matrixA: factorMatrix.values, sizeA: MatrixSize(rows: count, columns: count), matrixB: solution, sizeB: MatrixSize(rows: count, columns: 1))
76 | print("test result: \(testResults)")
77 |
78 | return solution
79 | }
80 |
81 | public func coefficientsFromScalingFunction(values: [Float], count: Int) -> [Float] {
82 | let halfT = ((values.count-1) / (count-1)) / 2
83 |
84 | var factorMatrix = Tensor(modeSizes: [count, count], repeatedValue: 0)
85 | var results = [Float](repeating: 0, count: count)
86 | for r in 0..= values.count) {continue}
92 | factorMatrix[r, c] = values[index]
93 | }
94 | }
95 |
96 | let solution = solveLinearEquationSystem(factorMatrix.values, factorMatrixSize: MatrixSize(rows: count, columns: count), results: results, resultsSize: MatrixSize(rows: count, columns: 1))
97 |
98 | return solution
99 | }
100 |
101 | public func newWaveletApproximation(_ currentApproximation: [Float], coefficients: [Float]) -> [Float] {
102 | let newLevel = 2 * (currentApproximation.count-1) / (coefficients.count-1)
103 | var newApproximation = [Float](repeating: 0, count: (coefficients.count-1) * newLevel + 1)
104 | let newValueCount = (coefficients.count-1) * (newLevel/2)
105 | print("new level: \(newLevel), value count: \(newApproximation.count), new values: \(newValueCount)")
106 |
107 | for t in 0..= newApproximation.count) {continue}
116 | value += coefficients[c] * newApproximation[index]
117 | }
118 | newApproximation[2*n+1] = value
119 | }
120 | return newApproximation
121 | }
122 |
123 | ///apprimate filter using the cascading algorithm
124 | public func newFilterApproximation(_ currentApproximation: [Float], coefficients: [Float]) -> [Float] {
125 | let newValueCount = 2*currentApproximation.count + coefficients.count - 2
126 | var newApproximation = [Float](repeating: 0, count: newValueCount)
127 |
128 | for j in 0..= 0 && index < currentApproximation.count) {
134 | currentValue += coefficients[k] * currentApproximation[index]
135 | }
136 |
137 | }
138 | }
139 | newApproximation[j] = currentValue
140 | }
141 |
142 | return newApproximation
143 | }
144 |
--------------------------------------------------------------------------------
/MultilinearMathTests/WaveletTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WaveletTests.swift
3 | // MultilinearMath
4 | //
5 | // Created by Vincent Herrmann on 14.08.16.
6 | // Copyright © 2016 Vincent Herrmann. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import MultilinearMath
11 |
12 | class WaveletTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testExample() {
25 | // This is an example of a functional test case.
26 | // Use XCTAssert and related functions to verify your tests produce the correct results.
27 | }
28 |
29 | func testDB4() {
30 | let db4: [Float] = [0.48296291314469025, 0.836516303737469, 0.22414386804185735, -0.12940952255092145].map({$0 * pow(2, 0.5)})
31 | //let db4: [Float] = [0.6830127, 1.1830127, 0.3169873, -0.1830127]
32 | let db4Wavelet = scalingFunction(from: db4, levels: 0)
33 | print("db4: \(db4Wavelet)")
34 | }
35 |
36 | func testDB6() {
37 | //let db6: [Float] = [0.035226291882100656, -0.08544127388224149, -0.13501102001039084, 0.4598775021193313, 0.8068915093133388, 0.3326705529509569]
38 | let db6: [Float] = [0.3326705529509569, 0.8068915093133388, 0.4598775021193313, -0.13501102001039084, -0.08544127388224149, 0.035226291882100656].map({$0 * pow(2, 0.5)})
39 |
40 |
41 | //let db6: [Float] = [0.47046721, 1.14111692, 0.650365, -0.19093442, -0.12083221, 0.0498175]
42 | let db6Wavelet = scalingFunction(from: db6, levels: 0)
43 | print("db6: \(db6Wavelet)")
44 | }
45 |
46 | func testDB8() {
47 |
48 | let db8: [Float] = [0.23037781330885523, 0.7148465705525415, 0.6308807679295904, -0.02798376941698385, -0.18703481171888114, 0.030841381835986965, 0.032883011666982945, -0.010597401784997278].map({$0 * pow(2, 0.5)})
49 |
50 |
51 | //let db8: [Float] = [1, 0, -2, 3, 4, 1, 1, -3]
52 | let db8Wavelet = scalingFunction(from: db8, levels: 0)
53 | print("db8: \(db8Wavelet)")
54 | }
55 |
56 | // func testFrequencyResponse() {
57 | // let db4: [Float] = [0.48296291314469025, 0.836516303737469, 0.22414386804185735, -0.12940952255092145].map({$0 * pow(2, 0.5)})
58 | // let spectrum = FIRFilter(coefficients: db4)
59 | // let v = Array(0..<99).map({(Float($0)/100)})
60 | // let fr = v.map({spectrum.frequencyResponse(6.28*$0 - 3.14)})
61 | // let impulseResponse = fr.map({$0.r * $0.i})
62 | // print("ir: \(impulseResponse)")
63 | // }
64 |
65 | func testDaubechiesCoefficients() {
66 | let db6 = calculateDaubechiesCoefficients(vanishingMoments: 3)
67 | let db6Tensor = Tensor(modeSizes: [6], values: db6)
68 | let target = Tensor(modeSizes: [6], values: [0.049817, -0.12083, -0.19093, 0.65037, 1.1411, 0.47047])
69 |
70 | let s = sum(db6Tensor[.a] - target[.a], overModes: [0])
71 |
72 | XCTAssert(abs(s.values[0]) < 0.01, "wrong daubechies 6 coefficients: \(db6)")
73 |
74 | print("daubechies 6 coefficients: \(db6)")
75 | }
76 |
77 | func testFlatDelayAllpass() {
78 | let d3 = flatDelayCoefficients(count: 3, delay: 0.5)
79 | print("d3: \(d3)")
80 |
81 | let d4 = flatDelayCoefficients(count: 4, delay: 0.5)
82 | print("d4: \(d4)")
83 | }
84 |
85 | func testComplexWavelet() {
86 | let cA4L2 = calculateComplexWaveletCoefficients(vanishingMoments: 4, delayCoefficients: 3, rootsOutsideUnitCircle: [1, 2])
87 | let real = cA4L2.map({$0.real})
88 | let imag = cA4L2.map({$0.imaginary})
89 |
90 | print("cA4L2midPhase real: \(real)")
91 | print("cA4L2midPhase imaginary: \(imag)")
92 |
93 | let scaling = scalingFunction(from: real, levels: 6)
94 | let reconstructedReal = coefficientsFromScalingFunction(values: scaling, count: 12)
95 | print("reconstructed real: \(reconstructedReal)")
96 |
97 |
98 | }
99 |
100 | func testForwardFWT() {
101 | let db4 = DaubechiesWavelet(vanishingMoments: 2)
102 | let signal = Array(0..<128).map({Float($0)/10}).map({sin(3*$0)})
103 | var currentSignal = signal
104 | var analysis: [[Float]] = []
105 |
106 | var a: (r0: [Float], r1: [Float]) = ([], [])
107 | for _ in 0..<4 {
108 | a = waveletTransformForwardStep(signal: currentSignal, h0: db4.h0, h1: db4.h1)
109 | currentSignal = a.r0
110 |
111 | analysis.append(a.r1)
112 | }
113 |
114 | analysis.append(a.r0)
115 | }
116 |
117 | func testPacketCode() {
118 | var c = WaveletPacket(values: [1, 2, 3, 4, 5, 6, 7], levels: [.scaling, .scaling, .wavelet])
119 | print("code: \(c.code), levels: \(c.levels), level: \(c.level), length: \(c.length)")
120 |
121 | c.addLevel(.scaling)
122 | print("code: \(c.code), levels: \(c.levels), level: \(c.level), length: \(c.length)")
123 |
124 | c.addLevel(.wavelet)
125 | print("code: \(c.code), levels: \(c.levels), level: \(c.level), length: \(c.length)")
126 |
127 | }
128 |
129 | func testPacketPlot() {
130 | let p1 = WaveletPacket(values: [0, 1, 2, 1], levels: [.wavelet])
131 | let p2 = WaveletPacket(values: [2, 0], levels: [.scaling, .wavelet])
132 | let p3 = WaveletPacket(values: [0, 1], levels: [.scaling, .scaling])
133 |
134 | let plot = FastWaveletPlot(packets: [p1, p2, p3])
135 |
136 | }
137 |
138 | func testPacketTransform() {
139 | let h0: [Float] = [0.6830127, 1.1830127, 0.3169873, -0.1830127]
140 | let w = Wavelet(h0: h0, f0: h0.reversed())
141 |
142 | let count: Int = 1024
143 | let length: Float = 30
144 | let xArray = Array(0..]) -> [Tensor]
17 | }
18 |
19 | protocol TensorFourierTransform {
20 | static var transformSetup: (vDSP_DFT_Setup?, vDSP_Length) -> OpaquePointer {get}
21 | static var transformFunction: (OpaquePointer, UnsafePointer, UnsafePointer, UnsafeMutablePointer, UnsafeMutablePointer) -> () {get}
22 | var modeSizes: [Int] {get}
23 | var transformSizes: [Int]! {get set}
24 | var dftSetups: [OpaquePointer] {get set}
25 | }
26 | extension TensorFourierTransform {
27 | mutating func setupTransform() {
28 | /// next biggest integer base 2 logarithms of the mode sizes
29 | let logSizes = modeSizes.map{Int(ceil(log2(Float($0))))}
30 | transformSizes = logSizes.map{Int(pow(2, Float($0)))}
31 | print("transform sizes: \(transformSizes)")
32 |
33 | //create dft setup for each mode
34 | dftSetups = []
35 | var currentSetup: OpaquePointer? = nil
36 | for size in transformSizes {
37 | currentSetup = Self.transformSetup(currentSetup, UInt(size))
38 | dftSetups.append(currentSetup!)
39 | }
40 | }
41 |
42 | func performFourierTransform(_ input: Tensor) -> Tensor {
43 | var inputTensor = input
44 | print("input tensor sizes: \(inputTensor.modeSizes)")
45 | var outputTensor = [Tensor(withPropertiesOf: inputTensor)]
46 |
47 | for mode in 0.. [Tensor] in
59 | let real = sourceData[slice: currentIndex][0...0, all].values
60 | let imag = sourceData[slice: currentIndex][1...1, all].values
61 |
62 | print("index \(currentIndex) real vector: \(real)")
63 | print("index \(currentIndex) imag vector: \(imag)")
64 |
65 | var realOutValues = [Float](repeating: 0, count: vectorSize)
66 | var imagOutValues = [Float](repeating: 0, count: vectorSize)
67 |
68 | Self.transformFunction(self.dftSetups[mode], real, imag, &realOutValues, &imagOutValues)
69 |
70 | let outputValues = realOutValues + imagOutValues
71 | let output = Tensor(modeSizes: [2, vectorSize], values: outputValues)
72 | // print("index \(currentIndex) real output: \(realOutValues)")
73 | // print("index \(currentIndex) imag output: \(imagOutValues)")
74 |
75 | return [output]
76 | },
77 | writeOutput: { (currentIndex, outerIndex, inputData, outputData) in
78 | outputData[0][slice: currentIndex] = inputData[0]
79 | })
80 |
81 | inputTensor = outputTensor[0]
82 | }
83 |
84 | return outputTensor[0]
85 | }
86 | }
87 |
88 | public struct FourierTransform: TensorFourierTransform, TensorOperationNode {
89 | public static var inputCount = 1
90 | public static var outputCount = 1
91 |
92 | static var transformSetup: (vDSP_DFT_Setup?, vDSP_Length) -> OpaquePointer = {(prevSetup, length) -> OpaquePointer in
93 | return vDSP_DFT_zop_CreateSetup(prevSetup, length, vDSP_DFT_Direction.FORWARD)!
94 | }
95 | static var transformFunction = {(setup, realIn, imagIn, realOut, imagOut) -> () in
96 | vDSP_DFT_Execute(setup, realIn, imagIn, realOut, imagOut)
97 | }
98 |
99 | var modeSizes: [Int]
100 | var transformSizes: [Int]!
101 | var dftSetups: [vDSP_DFT_Setup] = []
102 |
103 | public init(modeSizes: [Int]) {
104 | self.modeSizes = modeSizes
105 | setup()
106 | }
107 |
108 | mutating public func setup() {
109 | setupTransform()
110 | }
111 |
112 | public func execute(_ input: [Tensor]) -> [Tensor] {
113 | print("transform sizes: \(transformSizes)")
114 | let paddedInput = changeModeSizes(input[0], targetSizes: [2] + transformSizes)
115 | print("padded input sizes: \(paddedInput.modeSizes)")
116 | let output = performFourierTransform(paddedInput)
117 | return [output]
118 | }
119 | }
120 |
121 | public struct InverseFourierTransform: TensorFourierTransform, TensorOperationNode {
122 | public static var inputCount = 1
123 | public static var outputCount = 1
124 |
125 | static var transformSetup: (vDSP_DFT_Setup?, vDSP_Length) -> OpaquePointer = {(prevSetup, length) -> OpaquePointer in
126 | return vDSP_DFT_zop_CreateSetup(prevSetup, length, vDSP_DFT_Direction.INVERSE)!
127 | }
128 | static var transformFunction = {(setup, realIn, imagIn, realOut, imagOut) -> () in
129 | vDSP_DFT_Execute(setup, realIn, imagIn, realOut, imagOut)
130 | }
131 |
132 | var modeSizes: [Int]
133 | var transformSizes: [Int]!
134 | var dftSetups: [vDSP_DFT_Setup] = []
135 |
136 | public init(modeSizes: [Int]) {
137 | self.modeSizes = modeSizes
138 | setup()
139 | }
140 |
141 | mutating public func setup() {
142 | setupTransform()
143 | }
144 |
145 | public func execute(_ input: [Tensor]) -> [Tensor] {
146 | let factor = 1 / Float(transformSizes.reduce(1, {$0*$1}))
147 | let output = performFourierTransform(input[0]) * factor
148 | let scaledOutput = changeModeSizes(output, targetSizes: [2] + modeSizes)
149 | return [scaledOutput]
150 | }
151 | }
152 |
153 |
154 |
--------------------------------------------------------------------------------
/Sources/MPCA.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MPCA.swift
3 | // MultilinearMath
4 | //
5 | // Created by Vincent Herrmann on 27.03.16.
6 | // Copyright © 2016 Vincent Herrmann. All rights reserved.
7 | //
8 |
9 | //paper: H. Lu, K. N. Plataniotis, and A. N. Venetsanopoulos "MPCA: Multilinear Principal Component Analysis of Tensor Objects" July 2012
10 |
11 | import Foundation
12 |
13 | /// Multilinear Principal Component Analysis. Performs feature extraction by projecting a collection of samples with arbitrary mode count and sizes to a subspace while capturing most of the original variance.
14 | ///
15 | /// - Parameter data: Sample tensor. The first mode enumerates the different samples. The remaining modes constitute the specific sample. All sample elements should be centered, i.e. have mean 0.
16 | /// - Parameter projectionModeSizes: The mode sizes of the projected sample. Every mode has to be smaller of the as the corresponding mode in the original samples. `projectionModeSizes.count` = `data.modeCount-1`
17 | ///
18 | /// - Returns:
19 | /// `projectedData`:
The data projected to a subspace with the given mode sizes.
20 | /// `projectionMatrices`:
One matrix for each sample mode
21 | public func multilinearPCA(_ inputData: Tensor, projectionModeSizes: [Int]) -> (projectedData: Tensor, projectionMatrices: [Tensor]) {
22 |
23 | //Initialization
24 | let data = inputData.uniquelyIndexed()
25 | let sampleModeCount = data.modeCount - 1
26 | let maxLoops = sampleModeCount == 1 ? 1 : 20 //the simple PCA (sampleModeCount = 1) has a closed form solution
27 | let projectionDifferenceThreshold: Float = 0.001
28 |
29 | var projectionMatrices: [Tensor] = [] // U_n
30 | let projectionModeIndices = TensorIndex.uniqueIndexArray(sampleModeCount, excludedIndices: data.indices) //unique indices for projection matrices
31 | for n in 0..(diagonalWithModeSizes: modeSizes, repeatedValue: 1.0)
35 | thisProjectionMatrix.indices = [projectionModeIndices[n], data.indices[n+1]]
36 | projectionMatrices.append(thisProjectionMatrix)
37 |
38 | }
39 | var projectedData: Tensor = multilinearPCAProjection(data: data, projectionMatrices: projectionMatrices)
40 | var projectionScatter: Float = 0
41 | var newScatter = (projectedData * projectedData).values[0]
42 | print("multilinearPCA")
43 | print("initial projectionScatter: \(newScatter)")
44 |
45 | //Local Optimization
46 | for _ in 0.., oldProjectionMatrices: [Tensor]) -> [Tensor] {
65 |
66 | var newProjectionMatrices: [Tensor] = []
67 |
68 | //construct a new projectionMatrix for each mode
69 | for n in 0..(withPropertiesOf: oldProjectionMatrices[n], values: newValues)
85 | newProjectionMatrices.append(thisProjectionMatrix)
86 | }
87 |
88 | return newProjectionMatrices
89 | }
90 |
91 | /// Project the data tensor to a space with different dimensionality via the given projection matrices.
92 | ///
93 | /// - Parameter data: Sample tensor. The first mode enumerates the different samples. The remaining modes constitute the specific sample.
94 | /// - Parameter projectionMatrices: One projection matrix for each sample mode (either the MPCA projection matrices or the reconstruction matrices)
95 | /// - Parameter doNotProjectModes: The projection of these modes will be skipped. Although the content does not matter, a projection matrix is required nonetheless for these modes. The default value is an empty array.
96 | ///
97 | /// - Returns: The data projected with the given projection matrices.
98 | public func multilinearPCAProjection(data: Tensor, projectionMatrices: [Tensor], doNotProjectModes: [Int] = []) -> Tensor {
99 |
100 | var currentData = data
101 | for n in 0..]) -> [Tensor] {
121 | var reconstructionMatrices: [Tensor] = []
122 | for thisMatrix in projectionMatrices {
123 | let size = MatrixSize(rows: thisMatrix.modeSizes[0], columns: thisMatrix.modeSizes[1])
124 | let values = pseudoInverse(thisMatrix.values, size: size)
125 | var thisReconstructionMatrix = Tensor(modeSizes: [size.columns, size.rows], values: values)
126 | thisReconstructionMatrix.indices = thisMatrix.indices.reversed()
127 | reconstructionMatrices.append(thisReconstructionMatrix)
128 | }
129 | return reconstructionMatrices
130 | }
131 |
--------------------------------------------------------------------------------
/Sources/ParametricFunctions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ParametricFunctions.swift
3 | // MultilinearMath
4 | //
5 | // Created by Vincent Herrmann on 19.06.16.
6 | // Copyright © 2016 Vincent Herrmann. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public protocol ParametricTensorFunction {
12 | var parameters: [Tensor] {get set}
13 |
14 | func output(_ input: Tensor) -> Tensor
15 | func gradients(_ gradientWrtOutput: Tensor) -> (wrtInput: Tensor, wrtParameters: [Tensor])
16 | /// Substract the given values from the parameters. For gradient descent optimization algorithms
17 | mutating func updateParameters(_ subtrahends: [Tensor])
18 | }
19 |
20 | public protocol CostFunction: class {
21 | var estimator: ParametricTensorFunction {get set}
22 | var regularizers: [ParameterRegularizer?] {get}
23 |
24 | func costForEstimate(_ estimate: Tensor, target: Tensor) -> Float
25 | func gradientForEstimate(_ estimate: Tensor, target: Tensor) -> Tensor
26 | }
27 |
28 | public extension CostFunction {
29 | func updateParameters(_ subtrahends: [Tensor]) {
30 | let parameterRegularizations = estimator.parameters.combineWith(regularizers, combineFunction: { (parameter, regularizer) -> Tensor in
31 | if let r = regularizer {
32 | return r.regularizationGradient(parameter)
33 | } else {
34 | return Tensor(withPropertiesOf: parameter, repeatedValue: 0)
35 | }
36 | })
37 |
38 | estimator.updateParameters(subtrahends.combineWith(parameterRegularizations, combineFunction: {add(a: $0, outerModesA: [], b: $1, outerModesB: [])}))
39 | }
40 |
41 | func regularizedCostForEstimate(_ estimate: Tensor, target: Tensor) -> Float {
42 | let cost = self.costForEstimate(estimate, target: target)
43 |
44 | let regularizationCosts = estimator.parameters.combineWith(regularizers, combineFunction: { (parameter, regularizer) -> Float in
45 | return (regularizer != nil) ? regularizer!.regularizationCost(parameter) : 0
46 | })
47 |
48 | return cost + regularizationCosts.reduce(0, {$0 + $1})
49 | }
50 |
51 |
52 | public func numericalGradients(_ input: Tensor, target: Tensor, epsilon: Float = 0.01) -> [Tensor] {
53 | let estimate = estimator.output(input)
54 | let cost = costForEstimate(estimate, target: target)
55 |
56 | //check gradients
57 | var numericalGradients: [Tensor] = estimator.parameters
58 |
59 | for p in 0..) -> Float
92 | func regularizationGradient(_ parameter: Tensor) -> Tensor
93 | }
94 |
95 | public struct ParameterDecay: ParameterRegularizer {
96 | public var regularizationParameter: Float
97 |
98 | public init(decayRate: Float) {
99 | regularizationParameter = decayRate
100 | }
101 |
102 | public func regularizationCost(_ parameter: Tensor) -> Float {
103 | return multiply(a: parameter, remainingModesA: [], b: parameter, remainingModesB: []).values[0] * regularizationParameter
104 | }
105 | public func regularizationGradient(_ parameter: Tensor) -> Tensor {
106 | return parameter * regularizationParameter
107 | }
108 | }
109 |
110 | open class SquaredErrorCost: CostFunction {
111 | open var estimator: ParametricTensorFunction
112 | open var regularizers: [ParameterRegularizer?]
113 |
114 | public init(forEstimator: ParametricTensorFunction) {
115 | estimator = forEstimator
116 | regularizers = [ParameterRegularizer?](repeating: nil, count: estimator.parameters.count)
117 | }
118 |
119 | open func costForEstimate(_ estimate: Tensor, target: Tensor) -> Float {
120 | let exampleCount = Float(target.modeCount > 1 ? target.modeSizes[0] : 1)
121 |
122 | let error = substract(a: target, outerModesA: [], b: estimate, outerModesB: [])
123 | let cost = multiply(a: error, remainingModesA: [], b: error, remainingModesB: [])
124 | let scaledCost = cost.values[0] / exampleCount
125 |
126 | return cost.values[0] / exampleCount
127 | }
128 |
129 | open func gradientForEstimate(_ estimate: Tensor, target: Tensor) -> Tensor {
130 | let gradient = 2 * substract(a: estimate, outerModesA: [], b: target, outerModesB: [])
131 | return gradient
132 | }
133 | }
134 |
135 | open class NegLogClassificationCost: CostFunction {
136 | open var estimator: ParametricTensorFunction
137 | open var regularizers: [ParameterRegularizer?] {
138 | get {
139 | return [ParameterRegularizer?](repeating: nil, count: estimator.parameters.count)
140 | }
141 | }
142 |
143 | public init(forEstimator: ParametricTensorFunction) {
144 | estimator = forEstimator
145 | }
146 |
147 | open func costForEstimate(_ estimate: Tensor, target: Tensor) -> Float {
148 | let exampleCount = Float(target.modeCount > 1 ? target.modeSizes[0] : 1)
149 |
150 | let t1 = -target °* log(estimate)
151 | let t2 = (1-target) °* log(1-estimate)
152 | let cost = vectorSummation((t1-t2).values) / exampleCount
153 |
154 | return cost
155 | }
156 |
157 | open func gradientForEstimate(_ estimate: Tensor, target: Tensor) -> Tensor {
158 | let g1 = target °* (1/estimate)
159 | let g2 = (1-target) °* (1 / (1-estimate))
160 | let gradient = -(g1 - g2)
161 |
162 | return gradient
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/.build/debug/MultilinearMath.build/output-file-map.json:
--------------------------------------------------------------------------------
1 | {
2 | "": {
3 | "swift-dependencies": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/master.swiftdeps"
4 | },
5 | "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/Sources/AccelerateFunctionsFloat.swift": {
6 | "dependencies": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/AccelerateFunctionsFloat.d",
7 | "object": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/AccelerateFunctionsFloat.swift.o",
8 | "swiftmodule": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/AccelerateFunctionsFloat~partial.swiftmodule",
9 | "swift-dependencies": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/AccelerateFunctionsFloat.swiftdeps"
10 | },
11 | "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/Sources/main.swift": {
12 | "dependencies": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/main.d",
13 | "object": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/main.swift.o",
14 | "swiftmodule": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/main~partial.swiftmodule",
15 | "swift-dependencies": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/main.swiftdeps"
16 | },
17 | "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/Sources/MPCA.swift": {
18 | "dependencies": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/MPCA.d",
19 | "object": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/MPCA.swift.o",
20 | "swiftmodule": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/MPCA~partial.swiftmodule",
21 | "swift-dependencies": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/MPCA.swiftdeps"
22 | },
23 | "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/Sources/MultidimensionalData.swift": {
24 | "dependencies": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/MultidimensionalData.d",
25 | "object": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/MultidimensionalData.swift.o",
26 | "swiftmodule": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/MultidimensionalData~partial.swiftmodule",
27 | "swift-dependencies": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/MultidimensionalData.swiftdeps"
28 | },
29 | "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/Sources/SlicingSubscripts.swift": {
30 | "dependencies": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/SlicingSubscripts.d",
31 | "object": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/SlicingSubscripts.swift.o",
32 | "swiftmodule": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/SlicingSubscripts~partial.swiftmodule",
33 | "swift-dependencies": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/SlicingSubscripts.swiftdeps"
34 | },
35 | "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/Sources/TensorMultiplication.swift": {
36 | "dependencies": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/TensorMultiplication.d",
37 | "object": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/TensorMultiplication.swift.o",
38 | "swiftmodule": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/TensorMultiplication~partial.swiftmodule",
39 | "swift-dependencies": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/TensorMultiplication.swiftdeps"
40 | },
41 | "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/Sources/TensorOperations.swift": {
42 | "dependencies": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/TensorOperations.d",
43 | "object": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/TensorOperations.swift.o",
44 | "swiftmodule": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/TensorOperations~partial.swiftmodule",
45 | "swift-dependencies": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/TensorOperations.swiftdeps"
46 | },
47 | "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/Sources/Tensors.swift": {
48 | "dependencies": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/Tensors.d",
49 | "object": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/Tensors.swift.o",
50 | "swiftmodule": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/Tensors~partial.swiftmodule",
51 | "swift-dependencies": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/Tensors.swiftdeps"
52 | },
53 | "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/Sources/UMPCA.swift": {
54 | "dependencies": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/UMPCA.d",
55 | "object": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/UMPCA.swift.o",
56 | "swiftmodule": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/UMPCA~partial.swiftmodule",
57 | "swift-dependencies": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/UMPCA.swiftdeps"
58 | },
59 | "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/Sources/Utilities.swift": {
60 | "dependencies": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/Utilities.d",
61 | "object": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/Utilities.swift.o",
62 | "swiftmodule": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/Utilities~partial.swiftmodule",
63 | "swift-dependencies": "/Users/vincentherrmann/Documents/Software/SwiftPackages/multilinear-math/.build/debug/MultilinearMath.build/Utilities.swiftdeps"
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Sources/Utilities.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Utilities.swift
3 | // MultilinearMath
4 | //
5 | // Created by Vincent Herrmann on 27.03.16.
6 | // Copyright © 2016 Vincent Herrmann. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import Accelerate
11 |
12 | public protocol Number: Comparable {
13 | init(_ value: Int)
14 | init(_ value: Float)
15 | init(_ value: Double)
16 |
17 | static func + (lhs: Self, rhs: Self) -> Self
18 | static func - (lhs: Self, rhs: Self) -> Self
19 | static func * (lhs: Self, rhs: Self) -> Self
20 | static func / (lhs: Self, rhs: Self) -> Self
21 | }
22 |
23 | extension Double : Number {}
24 | extension Float : Number {}
25 | extension Int : Number {}
26 | extension Int64 : Number {}
27 |
28 | public protocol IntegerType {
29 | var value: Int {get}
30 | }
31 | extension Int: IntegerType {
32 | public var value: Int {
33 | get{
34 | return self
35 | }
36 | }
37 | }
38 |
39 | // credit for the UnsafeBuffer protocol to Chris Liscio https://github.com/liscio
40 | /// A CollectionType that can perfom functions on its Unsafe(Mutable)BufferPointer
41 | public protocol UnsafeBuffer: RandomAccessCollection {
42 | typealias IndexDistance = Int
43 |
44 | /// Perform the a function with a UnsafeBufferPointer to this collection
45 | func performWithUnsafeBufferPointer(_ body: (UnsafeBufferPointer) throws -> R) -> R?
46 | }
47 |
48 | public protocol UnsafeMutableBuffer: UnsafeBuffer, RandomAccessCollection {
49 | typealias IndexDistance = Int
50 |
51 | /// Perform the a function with a UnsafeMutableBufferPointer to this collection
52 | mutating func performWithUnsafeMutableBufferPointer(_ body: (inout UnsafeMutableBufferPointer) throws -> R) -> R?
53 | }
54 |
55 |
56 | extension Array : UnsafeMutableBuffer {
57 | public func performWithUnsafeBufferPointer(_ body: (UnsafeBufferPointer) throws -> R) -> R? {
58 | let value = try? withUnsafeBufferPointer(body)
59 | return value
60 | }
61 |
62 | mutating public func performWithUnsafeMutableBufferPointer(_ body: (inout UnsafeMutableBufferPointer) throws -> R) -> R? {
63 |
64 | let value = try? withUnsafeMutableBufferPointer(body)
65 | return value
66 | }
67 | }
68 | extension ArraySlice : UnsafeMutableBuffer {
69 | public func performWithUnsafeBufferPointer(_ body: (UnsafeBufferPointer) throws -> R) -> R? {
70 | let value = try? withUnsafeBufferPointer(body)
71 | return value
72 | }
73 |
74 | mutating public func performWithUnsafeMutableBufferPointer(_ body: (inout UnsafeMutableBufferPointer) throws -> R) -> R? {
75 | let value = try? withUnsafeMutableBufferPointer(body)
76 | return value
77 | }
78 | }
79 | extension UnsafeBufferPointer: UnsafeBuffer {
80 | public func performWithUnsafeBufferPointer(_ body: (UnsafeBufferPointer) throws -> R) -> R? {
81 | let value = try? body(self)
82 | return value
83 | }
84 | }
85 | extension UnsafeMutableBufferPointer: UnsafeMutableBuffer {
86 | public func performWithUnsafeBufferPointer(_ body: (UnsafeBufferPointer) throws -> R) -> R? {
87 | let thisPointer = UnsafeBufferPointer(start: baseAddress, count: count)
88 | let value = try? body(thisPointer)
89 | return value
90 | }
91 | public func performWithUnsafeMutableBufferPointer(_ body: (inout UnsafeMutableBufferPointer) throws -> R) -> R? {
92 | var thisPointer = self
93 | let value = try? body(&thisPointer)
94 | return value
95 | }
96 | }
97 |
98 | extension Collection {
99 | /// Return a copy of `self` with its elements shuffled
100 | func shuffle() -> [Iterator.Element] {
101 | var list = Array(self)
102 | list.shuffleInPlace()
103 | return list
104 | }
105 | }
106 |
107 | extension MutableCollection where IndexDistance == Int, Index == Int {
108 | /// Shuffle the elements of `self` in-place.
109 | mutating func shuffleInPlace() {
110 | // empty and single-element collections don't shuffle
111 | if count < 2 { return }
112 |
113 | for i in 0.. (_ arrayA: [A], arrayB: [B], combineFunction: (_ a: A, _ b: B) -> R) -> [R] {
124 | let length = min(arrayA.count, arrayB.count)
125 | var result = [R]()
126 | for i in 0..(_ array: [E], combineFunction: (_ t: Element, _ e: E) -> R) -> [R] {
134 | return arrayCombine(self, arrayB: array, combineFunction: combineFunction)
135 | }
136 |
137 | /// Safe access to array elements
138 | subscript (safe index: Int) -> Element? {
139 | return indices.contains(index) ? self[index] : nil
140 | }
141 | }
142 |
143 | public extension UnsafeBuffer where Iterator.Element: Equatable, Index == Int {
144 | ///remove the given values from this array
145 | func removeValues(_ values: [Iterator.Element]) -> [Iterator.Element] {
146 | var returnArray = Array(self)
147 | for value in values {
148 | if let index = returnArray.index(of: value) {
149 | returnArray.remove(at: index)
150 |
151 | }
152 | }
153 | return returnArray
154 | }
155 | }
156 |
157 | //public func squaredDistance(a: [Float], b: [Float]) -> Float {
158 | // return a.combineWith(b, combineFunction: {($0-$1)*($0-$1)}).reduce(0, combine: {$0+$1})
159 | //}
160 |
161 | public func meanSquaredError(target: [Float], result: [Float]) -> Float {
162 | assert(target.count == result.count)
163 | let factor = 1 / Float(target.count)
164 | let errors = zip(target, result).map({pow($0.0 - $0.1, 2)})
165 | return errors.reduce(0, {$0 + $1}) * factor
166 | }
167 |
168 | public func memoryAddress(_ o: UnsafeRawPointer) -> UnsafeRawPointer {
169 | return UnsafeRawPointer(bitPattern: unsafeBitCast(o, to: Int.self))!
170 | }
171 |
172 | public func printArrayAddress(_ array: inout [T]) {
173 | print("array memory address: \(memoryAddress(&array))")
174 | }
175 |
176 |
177 | public extension String {
178 |
179 | /// `Int8` value of the first character
180 | var charValue: Int8 {
181 | get {
182 | return (self.cString(using: String.Encoding.utf8)?[0])!
183 | }
184 | }
185 |
186 | subscript (i: Int) -> Character {
187 | return self[self.characters.index(self.startIndex, offsetBy: i)]
188 | }
189 |
190 | // subscript (r: CountableRange) -> String {
191 | // let start = characters.index(startIndex, offsetBy: r.lowerBound)
192 | // let end = <#T##String.CharacterView corresponding to `start`##String.CharacterView#>.index(start, offsetBy: r.upperBound - r.lowerBound)
193 | // return self[start.. = zeros()
15 | /// Cached activations of this layer of the last forward propagation, for being used in backpropagation of the gradients. Can be a minibatch.
16 | var currentActivations: Tensor = zeros()
17 |
18 | open var activationFunction: ActivationFunction
19 |
20 | var previousLayer: NeuralNetLayer?
21 | var nextLayer: NeuralNetLayer?
22 |
23 | /// mode for samples in batch
24 | let batch = TensorIndex.a
25 | /// mode for neurons in the previous layer
26 | let prev = TensorIndex.b
27 | /// mode for neurons in this layer
28 | let this = TensorIndex.c
29 |
30 | open var parameters: [Tensor] = []
31 |
32 | init(previousLayer: NeuralNetLayer? = nil, nextLayer: NeuralNetLayer? = nil, activationFunction: ActivationFunction = Sigmoid()) {
33 | self.previousLayer = previousLayer
34 | self.nextLayer = nextLayer
35 | self.activationFunction = activationFunction
36 | if let prev = previousLayer {
37 | prev.nextLayer = self
38 | }
39 | if let next = nextLayer {
40 | next.previousLayer = self
41 | }
42 | }
43 |
44 | open func output(_ input: Tensor) -> Tensor {
45 | currentPreactivations = input[batch, this]
46 | currentActivations = activationFunction.output(currentPreactivations)
47 | return currentActivations // [batch, this]
48 | }
49 |
50 | open func gradients(_ gradientWrtOutput: Tensor) -> (wrtInput: Tensor