├── .gitattributes
├── .github
└── workflows
│ ├── build_test.yml
│ ├── publish_coverage.yml
│ └── publish_docs.yml
├── .gitignore
├── .jazzy.yaml
├── Cartfile
├── LASwift.podspec
├── LASwift.xcodeproj
├── GeneratedModuleMap
│ └── CwlCatchExceptionSupport
│ │ └── module.modulemap
├── LASwift_Info.plist
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
└── xcshareddata
│ └── xcschemes
│ └── LASwift.xcscheme
├── LICENSE
├── Package.swift
├── README.md
├── Sources
├── Matrix.swift
├── MatrixAlgebra.swift
├── MatrixArithmetic.swift
├── MatrixExponent.swift
├── MatrixLeastSquare.swift
├── MatrixStatistics.swift
├── MatrixTrigonometry.swift
├── Numeric.swift
├── Operators.swift
├── Random.swift
├── Util.swift
├── Vector.swift
├── VectorArithmetic.swift
├── VectorExponent.swift
├── VectorStatistics.swift
└── VectorTrigonometry.swift
└── Tests
├── MatrixTests.swift
├── PerformanceTests.swift
└── VectorTests.swift
/.gitattributes:
--------------------------------------------------------------------------------
1 | Example/Pods/* linguist-vendored
2 |
--------------------------------------------------------------------------------
/.github/workflows/build_test.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a Swift project
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-swift
3 |
4 | name: Build
5 |
6 | on:
7 | push:
8 | branches:
9 | - master
10 | pull_request:
11 | branches:
12 | - master
13 |
14 | jobs:
15 | build:
16 |
17 | runs-on: macos-latest
18 |
19 | steps:
20 | - uses: actions/checkout@v3
21 | - name: Build
22 | run: swift build
23 | - name: Run tests
24 | run: swift test
25 |
--------------------------------------------------------------------------------
/.github/workflows/publish_coverage.yml:
--------------------------------------------------------------------------------
1 | name: Coverage
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 |
8 | jobs:
9 | build:
10 |
11 | runs-on: macos-latest
12 |
13 | steps:
14 | - uses: actions/checkout@v3
15 | - name: Run tests
16 | run: swift test --enable-code-coverage
17 | - name: Prepare code coverage
18 | run: xcrun llvm-cov export -format="lcov" .build/debug/LASwiftPackageTests.xctest/Contents/MacOS/LASwiftPackageTests -instr-profile .build/debug/codecov/default.profdata > info.lcov
19 | - name: Upload to codecov.io
20 | run: bash <(curl https://codecov.io/bash)
21 | env:
22 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
23 |
--------------------------------------------------------------------------------
/.github/workflows/publish_docs.yml:
--------------------------------------------------------------------------------
1 | name: Documentation
2 |
3 | on:
4 | release:
5 | types: [published]
6 |
7 | jobs:
8 | deploy_docs:
9 | runs-on: macos-latest
10 | steps:
11 | - uses: actions/checkout@v1
12 | - name: Publish Jazzy Docs
13 | uses: steven0351/publish-jazzy-docs@v1
14 | with:
15 | personal_access_token: ${{ secrets.ACCESS_TOKEN }}
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # OS X
2 | .DS_Store
3 |
4 | # Xcode
5 | build/
6 | .build/
7 | *.pbxuser
8 | !default.pbxuser
9 | *.mode1v3
10 | !default.mode1v3
11 | *.mode2v3
12 | !default.mode2v3
13 | *.perspectivev3
14 | !default.perspectivev3
15 | xcuserdata/
16 | *.xccheckout
17 | profile
18 | *.moved-aside
19 | DerivedData
20 | *.hmap
21 | *.ipa
22 | .swiftpm
23 |
24 | # Bundler
25 | .bundle
26 |
27 | *.lock
28 |
29 | Carthage
30 |
31 | Package.resolved
32 | Cartfile.resolved
33 |
34 |
--------------------------------------------------------------------------------
/.jazzy.yaml:
--------------------------------------------------------------------------------
1 | # podspec: LASwift.podspec
2 |
3 | author: Alexander Taraymovich
4 | github_url: https://github.com/AlexanderTar/LASwift/
5 |
6 | module: LASwift
7 | swift_build_tool: spm
8 | build_tool_arguments:
9 | - -Xswiftc
10 | - -swift-version
11 | - -Xswiftc
12 | - "5"
13 |
14 | min_acl: public
15 | skip_undocumented: true
16 | hide_documentation_coverage: true
17 | clean: true
18 |
19 | use_safe_filenames: true
20 |
--------------------------------------------------------------------------------
/Cartfile:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlexanderTar/LASwift/b0bdd4869e8aa2de37414b0cc2c4b739225b643f/Cartfile
--------------------------------------------------------------------------------
/LASwift.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # Be sure to run `pod lib lint LASwift.podspec' to ensure this is a
3 | # valid spec before submitting.
4 | #
5 | # Any lines starting with a # are optional, but their use is encouraged
6 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
7 | #
8 |
9 | Pod::Spec.new do |s|
10 | s.name = 'LASwift'
11 | s.version = '0.3.2'
12 | s.summary = 'Linear algebra library for Swift language'
13 |
14 | s.description = <<-DESC
15 | This library provides most of linear algebra operations on vectors and matrices
16 | required to implement machine learning algorithms. Library syntax is inspired by
17 | Matlab matrix manipulation and Haskell linear algebra library 'hmatrix'
18 | DESC
19 |
20 | s.homepage = 'https://github.com/alexandertar/LASwift'
21 | s.license = { :type => 'BSD-3-Clause', :file => 'LICENSE' }
22 | s.author = { 'Alexander Taraymovich' => 'taraymovich@me.com' }
23 | s.source = { :git => 'https://github.com/alexandertar/LASwift.git', :tag => s.version.to_s }
24 |
25 | s.ios.deployment_target = '12.0'
26 | s.osx.deployment_target = '10.13'
27 | s.tvos.deployment_target = '12.0'
28 | s.watchos.deployment_target = '6.0'
29 |
30 | s.swift_version = '5.0'
31 |
32 | s.frameworks = 'Accelerate'
33 |
34 | s.source_files = 'Sources/**/*'
35 | end
36 |
--------------------------------------------------------------------------------
/LASwift.xcodeproj/GeneratedModuleMap/CwlCatchExceptionSupport/module.modulemap:
--------------------------------------------------------------------------------
1 | module CwlCatchExceptionSupport {
2 | umbrella "/Users/alexandertar/git/LASwift/.build/checkouts/CwlCatchException/Sources/CwlCatchExceptionSupport/include"
3 | export *
4 | }
5 |
--------------------------------------------------------------------------------
/LASwift.xcodeproj/LASwift_Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | CFBundleDevelopmentRegion
5 | en
6 | CFBundleExecutable
7 | $(EXECUTABLE_NAME)
8 | CFBundleIdentifier
9 | $(PRODUCT_BUNDLE_IDENTIFIER)
10 | CFBundleInfoDictionaryVersion
11 | 6.0
12 | CFBundleName
13 | $(PRODUCT_NAME)
14 | CFBundlePackageType
15 | FMWK
16 | CFBundleShortVersionString
17 | 1.0
18 | CFBundleSignature
19 | ????
20 | CFBundleVersion
21 | $(CURRENT_PROJECT_VERSION)
22 | NSPrincipalClass
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/LASwift.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | OBJ_229 /* Matrix.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_8 /* Matrix.swift */; };
11 | OBJ_230 /* MatrixAlgebra.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_9 /* MatrixAlgebra.swift */; };
12 | OBJ_231 /* MatrixArithmetic.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_10 /* MatrixArithmetic.swift */; };
13 | OBJ_232 /* MatrixExponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_11 /* MatrixExponent.swift */; };
14 | OBJ_233 /* MatrixLeastSquare.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_12 /* MatrixLeastSquare.swift */; };
15 | OBJ_234 /* MatrixStatistics.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_13 /* MatrixStatistics.swift */; };
16 | OBJ_235 /* MatrixTrigonometry.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_14 /* MatrixTrigonometry.swift */; };
17 | OBJ_236 /* Numeric.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_15 /* Numeric.swift */; };
18 | OBJ_237 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_16 /* Operators.swift */; };
19 | OBJ_238 /* Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_17 /* Random.swift */; };
20 | OBJ_239 /* Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_18 /* Util.swift */; };
21 | OBJ_240 /* Vector.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_19 /* Vector.swift */; };
22 | OBJ_241 /* VectorArithmetic.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_20 /* VectorArithmetic.swift */; };
23 | OBJ_242 /* VectorExponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_21 /* VectorExponent.swift */; };
24 | OBJ_243 /* VectorStatistics.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_22 /* VectorStatistics.swift */; };
25 | OBJ_244 /* VectorTrigonometry.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_23 /* VectorTrigonometry.swift */; };
26 | /* End PBXBuildFile section */
27 |
28 | /* Begin PBXFileReference section */
29 | OBJ_10 /* MatrixArithmetic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatrixArithmetic.swift; sourceTree = ""; };
30 | OBJ_11 /* MatrixExponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatrixExponent.swift; sourceTree = ""; };
31 | OBJ_12 /* MatrixLeastSquare.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatrixLeastSquare.swift; sourceTree = ""; };
32 | OBJ_13 /* MatrixStatistics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatrixStatistics.swift; sourceTree = ""; };
33 | OBJ_14 /* MatrixTrigonometry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatrixTrigonometry.swift; sourceTree = ""; };
34 | OBJ_15 /* Numeric.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Numeric.swift; sourceTree = ""; };
35 | OBJ_159 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = ""; };
36 | OBJ_16 /* Operators.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Operators.swift; sourceTree = ""; };
37 | OBJ_160 /* Cartfile */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cartfile; sourceTree = ""; };
38 | OBJ_161 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
39 | OBJ_162 /* Rakefile */ = {isa = PBXFileReference; lastKnownFileType = text; path = Rakefile; sourceTree = ""; };
40 | OBJ_163 /* LASwift.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = LASwift.podspec; sourceTree = ""; };
41 | OBJ_17 /* Random.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Random.swift; sourceTree = ""; };
42 | OBJ_18 /* Util.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Util.swift; sourceTree = ""; };
43 | OBJ_19 /* Vector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Vector.swift; sourceTree = ""; };
44 | OBJ_20 /* VectorArithmetic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VectorArithmetic.swift; sourceTree = ""; };
45 | OBJ_21 /* VectorExponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VectorExponent.swift; sourceTree = ""; };
46 | OBJ_22 /* VectorStatistics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VectorStatistics.swift; sourceTree = ""; };
47 | OBJ_23 /* VectorTrigonometry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VectorTrigonometry.swift; sourceTree = ""; };
48 | OBJ_6 /* Package.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; };
49 | OBJ_8 /* Matrix.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Matrix.swift; sourceTree = ""; };
50 | OBJ_9 /* MatrixAlgebra.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatrixAlgebra.swift; sourceTree = ""; };
51 | "laswift::LASwift::Product" /* LASwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = LASwift.framework; sourceTree = BUILT_PRODUCTS_DIR; };
52 | /* End PBXFileReference section */
53 |
54 | /* Begin PBXFrameworksBuildPhase section */
55 | OBJ_245 /* Frameworks */ = {
56 | isa = PBXFrameworksBuildPhase;
57 | buildActionMask = 0;
58 | files = (
59 | );
60 | runOnlyForDeploymentPostprocessing = 0;
61 | };
62 | /* End PBXFrameworksBuildPhase section */
63 |
64 | /* Begin PBXGroup section */
65 | OBJ_147 /* Products */ = {
66 | isa = PBXGroup;
67 | children = (
68 | "laswift::LASwift::Product" /* LASwift.framework */,
69 | );
70 | name = Products;
71 | sourceTree = BUILT_PRODUCTS_DIR;
72 | };
73 | OBJ_5 /* */ = {
74 | isa = PBXGroup;
75 | children = (
76 | OBJ_6 /* Package.swift */,
77 | OBJ_7 /* Sources */,
78 | OBJ_147 /* Products */,
79 | OBJ_159 /* LICENSE */,
80 | OBJ_160 /* Cartfile */,
81 | OBJ_161 /* README.md */,
82 | OBJ_162 /* Rakefile */,
83 | OBJ_163 /* LASwift.podspec */,
84 | );
85 | name = "";
86 | sourceTree = "";
87 | };
88 | OBJ_7 /* Sources */ = {
89 | isa = PBXGroup;
90 | children = (
91 | OBJ_8 /* Matrix.swift */,
92 | OBJ_9 /* MatrixAlgebra.swift */,
93 | OBJ_10 /* MatrixArithmetic.swift */,
94 | OBJ_11 /* MatrixExponent.swift */,
95 | OBJ_12 /* MatrixLeastSquare.swift */,
96 | OBJ_13 /* MatrixStatistics.swift */,
97 | OBJ_14 /* MatrixTrigonometry.swift */,
98 | OBJ_15 /* Numeric.swift */,
99 | OBJ_16 /* Operators.swift */,
100 | OBJ_17 /* Random.swift */,
101 | OBJ_18 /* Util.swift */,
102 | OBJ_19 /* Vector.swift */,
103 | OBJ_20 /* VectorArithmetic.swift */,
104 | OBJ_21 /* VectorExponent.swift */,
105 | OBJ_22 /* VectorStatistics.swift */,
106 | OBJ_23 /* VectorTrigonometry.swift */,
107 | );
108 | path = Sources;
109 | sourceTree = SOURCE_ROOT;
110 | };
111 | /* End PBXGroup section */
112 |
113 | /* Begin PBXNativeTarget section */
114 | "laswift::LASwift" /* LASwift */ = {
115 | isa = PBXNativeTarget;
116 | buildConfigurationList = OBJ_225 /* Build configuration list for PBXNativeTarget "LASwift" */;
117 | buildPhases = (
118 | OBJ_228 /* Sources */,
119 | OBJ_245 /* Frameworks */,
120 | );
121 | buildRules = (
122 | );
123 | dependencies = (
124 | );
125 | name = LASwift;
126 | productName = LASwift;
127 | productReference = "laswift::LASwift::Product" /* LASwift.framework */;
128 | productType = "com.apple.product-type.framework";
129 | };
130 | /* End PBXNativeTarget section */
131 |
132 | /* Begin PBXProject section */
133 | OBJ_1 /* Project object */ = {
134 | isa = PBXProject;
135 | attributes = {
136 | LastSwiftMigration = 9999;
137 | LastUpgradeCheck = 9999;
138 | };
139 | buildConfigurationList = OBJ_2 /* Build configuration list for PBXProject "LASwift" */;
140 | compatibilityVersion = "Xcode 3.2";
141 | developmentRegion = en;
142 | hasScannedForEncodings = 0;
143 | knownRegions = (
144 | en,
145 | );
146 | mainGroup = OBJ_5 /* */;
147 | productRefGroup = OBJ_147 /* Products */;
148 | projectDirPath = "";
149 | projectRoot = "";
150 | targets = (
151 | "laswift::LASwift" /* LASwift */,
152 | );
153 | };
154 | /* End PBXProject section */
155 |
156 | /* Begin PBXSourcesBuildPhase section */
157 | OBJ_228 /* Sources */ = {
158 | isa = PBXSourcesBuildPhase;
159 | buildActionMask = 0;
160 | files = (
161 | OBJ_229 /* Matrix.swift in Sources */,
162 | OBJ_230 /* MatrixAlgebra.swift in Sources */,
163 | OBJ_231 /* MatrixArithmetic.swift in Sources */,
164 | OBJ_232 /* MatrixExponent.swift in Sources */,
165 | OBJ_233 /* MatrixLeastSquare.swift in Sources */,
166 | OBJ_234 /* MatrixStatistics.swift in Sources */,
167 | OBJ_235 /* MatrixTrigonometry.swift in Sources */,
168 | OBJ_236 /* Numeric.swift in Sources */,
169 | OBJ_237 /* Operators.swift in Sources */,
170 | OBJ_238 /* Random.swift in Sources */,
171 | OBJ_239 /* Util.swift in Sources */,
172 | OBJ_240 /* Vector.swift in Sources */,
173 | OBJ_241 /* VectorArithmetic.swift in Sources */,
174 | OBJ_242 /* VectorExponent.swift in Sources */,
175 | OBJ_243 /* VectorStatistics.swift in Sources */,
176 | OBJ_244 /* VectorTrigonometry.swift in Sources */,
177 | );
178 | runOnlyForDeploymentPostprocessing = 0;
179 | };
180 | /* End PBXSourcesBuildPhase section */
181 |
182 | /* Begin XCBuildConfiguration section */
183 | OBJ_226 /* Debug */ = {
184 | isa = XCBuildConfiguration;
185 | buildSettings = {
186 | CURRENT_PROJECT_VERSION = 1;
187 | DRIVERKIT_DEPLOYMENT_TARGET = 19.0;
188 | ENABLE_TESTABILITY = YES;
189 | FRAMEWORK_SEARCH_PATHS = (
190 | "$(inherited)",
191 | "$(PLATFORM_DIR)/Developer/Library/Frameworks",
192 | );
193 | HEADER_SEARCH_PATHS = "$(inherited)";
194 | INFOPLIST_FILE = LASwift.xcodeproj/LASwift_Info.plist;
195 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
196 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/macosx";
197 | MACOSX_DEPLOYMENT_TARGET = 10.13;
198 | OTHER_CFLAGS = "$(inherited)";
199 | OTHER_LDFLAGS = "$(inherited)";
200 | OTHER_SWIFT_FLAGS = "$(inherited)";
201 | PRODUCT_BUNDLE_IDENTIFIER = LASwift;
202 | PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)";
203 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
204 | SKIP_INSTALL = YES;
205 | SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator macosx watchos watchsimulator";
206 | SUPPORTS_MACCATALYST = YES;
207 | SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
208 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)";
209 | SWIFT_VERSION = 5.0;
210 | TARGETED_DEVICE_FAMILY = "1,3,4";
211 | TARGET_NAME = LASwift;
212 | TVOS_DEPLOYMENT_TARGET = 12.0;
213 | WATCHOS_DEPLOYMENT_TARGET = 6.0;
214 | };
215 | name = Debug;
216 | };
217 | OBJ_227 /* Release */ = {
218 | isa = XCBuildConfiguration;
219 | buildSettings = {
220 | CURRENT_PROJECT_VERSION = 1;
221 | DRIVERKIT_DEPLOYMENT_TARGET = 19.0;
222 | ENABLE_TESTABILITY = YES;
223 | FRAMEWORK_SEARCH_PATHS = (
224 | "$(inherited)",
225 | "$(PLATFORM_DIR)/Developer/Library/Frameworks",
226 | );
227 | HEADER_SEARCH_PATHS = "$(inherited)";
228 | INFOPLIST_FILE = LASwift.xcodeproj/LASwift_Info.plist;
229 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
230 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/macosx";
231 | MACOSX_DEPLOYMENT_TARGET = 10.13;
232 | OTHER_CFLAGS = "$(inherited)";
233 | OTHER_LDFLAGS = "$(inherited)";
234 | OTHER_SWIFT_FLAGS = "$(inherited)";
235 | PRODUCT_BUNDLE_IDENTIFIER = LASwift;
236 | PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)";
237 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
238 | SKIP_INSTALL = YES;
239 | SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator macosx watchos watchsimulator";
240 | SUPPORTS_MACCATALYST = YES;
241 | SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
242 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)";
243 | SWIFT_VERSION = 5.0;
244 | TARGETED_DEVICE_FAMILY = "1,3,4";
245 | TARGET_NAME = LASwift;
246 | TVOS_DEPLOYMENT_TARGET = 12.0;
247 | WATCHOS_DEPLOYMENT_TARGET = 6.0;
248 | };
249 | name = Release;
250 | };
251 | OBJ_3 /* Debug */ = {
252 | isa = XCBuildConfiguration;
253 | buildSettings = {
254 | CLANG_ENABLE_OBJC_ARC = YES;
255 | COMBINE_HIDPI_IMAGES = YES;
256 | COPY_PHASE_STRIP = NO;
257 | DEBUG_INFORMATION_FORMAT = dwarf;
258 | DYLIB_INSTALL_NAME_BASE = "@rpath";
259 | ENABLE_NS_ASSERTIONS = YES;
260 | GCC_OPTIMIZATION_LEVEL = 0;
261 | GCC_PREPROCESSOR_DEFINITIONS = (
262 | "$(inherited)",
263 | "SWIFT_PACKAGE=1",
264 | "DEBUG=1",
265 | );
266 | MACOSX_DEPLOYMENT_TARGET = 10.10;
267 | ONLY_ACTIVE_ARCH = YES;
268 | OTHER_SWIFT_FLAGS = "$(inherited) -DXcode";
269 | PRODUCT_NAME = "$(TARGET_NAME)";
270 | SDKROOT = macosx;
271 | SUPPORTED_PLATFORMS = "$(AVAILABLE_PLATFORMS)";
272 | SUPPORTS_MACCATALYST = YES;
273 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) SWIFT_PACKAGE DEBUG";
274 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
275 | USE_HEADERMAP = NO;
276 | };
277 | name = Debug;
278 | };
279 | OBJ_4 /* Release */ = {
280 | isa = XCBuildConfiguration;
281 | buildSettings = {
282 | CLANG_ENABLE_OBJC_ARC = YES;
283 | COMBINE_HIDPI_IMAGES = YES;
284 | COPY_PHASE_STRIP = YES;
285 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
286 | DYLIB_INSTALL_NAME_BASE = "@rpath";
287 | GCC_OPTIMIZATION_LEVEL = s;
288 | GCC_PREPROCESSOR_DEFINITIONS = (
289 | "$(inherited)",
290 | "SWIFT_PACKAGE=1",
291 | );
292 | MACOSX_DEPLOYMENT_TARGET = 10.10;
293 | OTHER_SWIFT_FLAGS = "$(inherited) -DXcode";
294 | PRODUCT_NAME = "$(TARGET_NAME)";
295 | SDKROOT = macosx;
296 | SUPPORTED_PLATFORMS = "$(AVAILABLE_PLATFORMS)";
297 | SUPPORTS_MACCATALYST = YES;
298 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) SWIFT_PACKAGE";
299 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
300 | USE_HEADERMAP = NO;
301 | };
302 | name = Release;
303 | };
304 | /* End XCBuildConfiguration section */
305 |
306 | /* Begin XCConfigurationList section */
307 | OBJ_2 /* Build configuration list for PBXProject "LASwift" */ = {
308 | isa = XCConfigurationList;
309 | buildConfigurations = (
310 | OBJ_3 /* Debug */,
311 | OBJ_4 /* Release */,
312 | );
313 | defaultConfigurationIsVisible = 0;
314 | defaultConfigurationName = Release;
315 | };
316 | OBJ_225 /* Build configuration list for PBXNativeTarget "LASwift" */ = {
317 | isa = XCConfigurationList;
318 | buildConfigurations = (
319 | OBJ_226 /* Debug */,
320 | OBJ_227 /* Release */,
321 | );
322 | defaultConfigurationIsVisible = 0;
323 | defaultConfigurationName = Release;
324 | };
325 | /* End XCConfigurationList section */
326 | };
327 | rootObject = OBJ_1 /* Project object */;
328 | }
329 |
--------------------------------------------------------------------------------
/LASwift.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
--------------------------------------------------------------------------------
/LASwift.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/LASwift.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded
6 |
7 |
8 |
--------------------------------------------------------------------------------
/LASwift.xcodeproj/xcshareddata/xcschemes/LASwift.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
57 |
58 |
59 |
60 |
62 |
63 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2017 Alexander Taraymovich
2 |
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are met:
7 |
8 | * Redistributions of source code must retain the above copyright
9 | notice, this list of conditions and the following disclaimer.
10 |
11 | * Redistributions in binary form must reproduce the above
12 | copyright notice, this list of conditions and the following
13 | disclaimer in the documentation and/or other materials provided
14 | with the distribution.
15 |
16 | * Neither the name of Alexander Taraymovich nor the names of other
17 | contributors may be used to endorse or promote products derived
18 | from this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.1
2 | // Package.swift
3 | //
4 | // Copyright (c) 2017 Alexander Taraymovich
5 | // All rights reserved.
6 | //
7 | // This software may be modified and distributed under the terms
8 | // of the BSD license. See the LICENSE file for details.
9 | import PackageDescription
10 |
11 | let package = Package(
12 | name: "LASwift",
13 | platforms: [
14 | .macOS(.v10_13), .iOS(.v12), .tvOS(.v12), .watchOS(.v6)
15 | ],
16 | products: [
17 | .library(name: "LASwift", targets: ["LASwift"])
18 | ],
19 | dependencies: [
20 | .package(url: "https://github.com/Quick/Quick.git", from: "5.0.0"),
21 | .package(url: "https://github.com/Quick/Nimble.git", from: "10.0.0")
22 | ],
23 | targets: [
24 | .target(
25 | name: "LASwift",
26 | dependencies: [],
27 | path: "Sources"),
28 | .testTarget(
29 | name: "LASwiftTests",
30 | dependencies: ["LASwift", "Quick", "Nimble"],
31 | path: "Tests")
32 | ],
33 | swiftLanguageVersions: [.v5]
34 | )
35 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # LASwift
2 |
3 | [](https://github.com/AlexanderTar/LASwift/actions/workflows/build_test.yml)
4 | [](https://codecov.io/gh/AlexanderTar/LASwift)
5 | [](https://github.com/Carthage/Carthage)
6 | [](https://alexandertar.github.io/LASwift/index.html)
7 | [](https://raw.githubusercontent.com/AlexanderTar/LASwift/master/LICENSE)
8 | [](http://cocoapods.org/pods/LASwift)
9 | [](http://cocoapods.org/pods/LASwift)
10 |
11 | LASwift provides most of linear algebra operations on vectors and matrices
12 | required to implement machine learning algorithms. Library syntax is inspired by
13 | Matlab matrix manipulation and Haskell linear algebra library 'hmatrix'. LASwift is
14 | using high-performant calculations provided by LAPACK, BLAS and vDSP through Apple
15 | Accelerate framework.
16 |
17 | ## Currently supported
18 |
19 | Following operations are fully supported for both vectors and matrices:
20 |
21 | - Arithmetic operations (addition, substraction, multiplication, division, absolute value)
22 | - Exponential functions (raise to power, exponent, logarithms)
23 | - Trigonometric functions (sine, cosine, tangent)
24 | - Statistics functions (max, min, mean value, standard deviation)
25 |
26 | Linear algebra operations on matrices:
27 |
28 | - Inversion
29 | - Transposition
30 | - Matrix power (integer values)
31 | - Eigenvectors and eigenvalues
32 | - Singular value decomposition
33 |
34 | Following matrix manipulation operations are supported:
35 |
36 | - Concatenation
37 | - Slicing
38 |
39 | ## Requirements
40 |
41 | - iOS 12.0+ / Mac OS X 10.13+ / tvOS 12.0+ / watchOS 2.0+
42 | - Xcode 12.0+
43 | - Swift 5.0+
44 |
45 | ## Benchmarks
46 |
47 | Refer to [linalg-benchmarks](https://github.com/Alexander-Ignatyev/linalg-benchmarks) project
48 | regarding basic benchmarking of latest version of LASwift against most popular linear
49 | algebra libraries (Haskell hmatrix, Python NumPy, Octave, Go gonum-matrix).
50 |
51 | ## Installation
52 |
53 | #### CocoaPods
54 |
55 | Install CocoaPods if not already available:
56 |
57 | ``` bash
58 | $ [sudo] gem install cocoapods
59 | $ pod setup
60 | ```
61 | Go to the directory of your Xcode project, and Create and Edit your *Podfile* and add _LASwift_:
62 |
63 | ``` bash
64 | $ cd /path/to/MyProject
65 | $ touch Podfile
66 | $ edit Podfile
67 | source 'https://github.com/CocoaPods/Specs.git'
68 | platform :ios, '8.0'
69 |
70 | use_frameworks!
71 | pod 'LASwift', '~> 0.3.2'
72 | ```
73 |
74 | Install into your project:
75 |
76 | ``` bash
77 | $ pod install
78 | ```
79 |
80 | Open your project in Xcode from the .xcworkspace file (not the usual project file):
81 |
82 | ``` bash
83 | $ open MyProject.xcworkspace
84 | ```
85 |
86 | You can now `import LASwift` framework into your files.
87 |
88 | #### Carthage
89 |
90 | [Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that automates the process of adding frameworks to your Cocoa application.
91 |
92 | You can install Carthage with [Homebrew](http://brew.sh/) using the following command:
93 |
94 | ```bash
95 | $ brew update
96 | $ brew install carthage
97 | ```
98 |
99 | To integrate `LASwift` into your Xcode project using Carthage, specify it in your `Cartfile` file:
100 |
101 | ```ogdl
102 | github "alexandertar/LASwift" >= 0.3.2
103 | ```
104 |
105 | #### Swift Package Manager
106 | You can use [The Swift Package Manager](https://swift.org/package-manager) to install `LASwift` by adding the proper description to your `Package.swift` file:
107 | ```swift
108 | import PackageDescription
109 |
110 | let package = Package(
111 | name: "YOUR_PROJECT_NAME",
112 | targets: [],
113 | dependencies: [
114 | .Package(url: "https://github.com/alexandertar/LASwift", versions: "0.3.2" ..< Version.max)
115 | ]
116 | )
117 | ```
118 |
119 | Note that the [Swift Package Manager](https://swift.org/package-manager) is still in early design and development, for more information checkout its [GitHub Page](https://github.com/apple/swift-package-manager).
120 |
121 | ## Contribution
122 |
123 | Currently implemented functionality should be sufficient enough to implement machine learning
124 | algorithms (as this was an initial purpose). However, if you find something missing or wish to add
125 | extra features, feel free to submit pull-requests or create issues with proposals.
126 |
127 | ## Author
128 |
129 | Alexander Taraymovich, taraymovich@me.com
130 |
131 | ## License
132 |
133 | LASwift is available under the BSD-3-Clause license. See the LICENSE file for more info.
134 |
--------------------------------------------------------------------------------
/Sources/Matrix.swift:
--------------------------------------------------------------------------------
1 | // Matrix.swift
2 | //
3 | // Copyright (c) 2017 Alexander Taraymovich
4 | // All rights reserved.
5 | //
6 | // This software may be modified and distributed under the terms
7 | // of the BSD license. See the LICENSE file for details.
8 |
9 | import Accelerate
10 |
11 | // MARK: - One-line creators for matrices
12 |
13 | /// Create a matrix of zeros.
14 | ///
15 | /// - Parameters:
16 | /// - rows: number of rows
17 | /// - cols: number of columns
18 | /// - Returns: zeros matrix of specified size
19 | public func zeros(_ rows: Int, _ cols: Int) -> Matrix {
20 | precondition(rows > 0 && cols > 0, "Matrix dimensions must be positive")
21 | return Matrix(rows, cols, 0.0)
22 | }
23 |
24 | /// Create a matrix of zeros.
25 | ///
26 | /// - Parameters:
27 | /// - m: Matrix
28 | /// - Returns: matrix of zeros with same size as input
29 | public func zeros(like m: Matrix) -> Matrix {
30 | return zeros(m.rows, m.cols)
31 | }
32 |
33 | /// Create a matrix of ones.
34 | ///
35 | /// - Parameters:
36 | /// - rows: number of rows
37 | /// - cols: number of columns
38 | /// - Returns: ones matrix of specified size
39 | public func ones(_ rows: Int, _ cols: Int) -> Matrix {
40 | precondition(rows > 0 && cols > 0, "Matrix dimensions must be positive")
41 | return Matrix(rows, cols, 1.0)
42 | }
43 |
44 | /// Create a matrix of ones.
45 | ///
46 | /// - Parameters:
47 | /// - m: Matrix
48 | /// - Returns: matrix of ones with same size as input
49 | public func ones(like m: Matrix) -> Matrix {
50 | return ones(m.rows, m.cols)
51 | }
52 |
53 | /// Create a matrix of uniformly distributed on [0, 1) interval random values.
54 | ///
55 | /// - Parameters:
56 | /// - rows: number of rows
57 | /// - cols: number of columns
58 | /// - Returns: random values matrix of specified size
59 | public func rand(_ rows: Int, _ cols: Int) -> Matrix {
60 | precondition(rows > 0 && cols > 0, "Matrix dimensions must be positive")
61 | return Matrix(rows, cols, rand(rows * cols))
62 | }
63 |
64 | /// Create a matrix of normally distibuted random values.
65 | ///
66 | /// - Parameters:
67 | /// - rows: number of rows
68 | /// - cols: number of columns
69 | /// - Returns: random values matrix of specified size
70 | public func randn(_ rows: Int, _ cols: Int) -> Matrix {
71 | precondition(rows > 0 && cols > 0, "Matrix dimensions must be positive")
72 | return Matrix(rows, cols, randn(rows * cols))
73 | }
74 |
75 | /// Create a matrix with ones on the main diagonal and zeros elsewhere.
76 | ///
77 | /// - Parameters:
78 | /// - rows: number of rows
79 | /// - cols: number of columns
80 | /// - Returns: identity matrix of specified size
81 | public func eye(_ rows: Int, _ cols: Int) -> Matrix {
82 | precondition(rows > 0 && cols > 0, "Matrix dimensions must be positive")
83 | return Matrix((0.. Vector in
84 | var row = Vector(repeating: 0.0, count: cols)
85 | if (i < cols) {
86 | row[i] = 1.0
87 | }
88 | return row
89 | })
90 | }
91 |
92 | /// Create a square matrix with specified values on the main diagonal and zeros elsewhere.
93 | ///
94 | /// - Parameters:
95 | /// - v: matrix of values with one column
96 | /// - Returns: square diagonal matrix with specified values
97 | public func diag(_ v: Matrix) -> Matrix {
98 | precondition(v.cols == 1, "Input must be a vector")
99 | return diag(v.flat)
100 | }
101 |
102 | /// Create a square matrix with specified values on the main diagonal and zeros elsewhere.
103 | ///
104 | /// - Parameters:
105 | /// - v: vector of values
106 | /// - Returns: square diagonal matrix with specified values
107 | public func diag(_ v: Vector) -> Matrix {
108 | let count = v.count
109 | let m: Matrix = zeros(count, count)
110 | _ = (0.. Matrix {
122 | precondition(v.cols == 1, "Input must be a vector")
123 | return diag(rows, cols, v.flat)
124 | }
125 |
126 | /// Create a matrix with specified values on the main diagonal and zeros elsewhere.
127 | ///
128 | /// - Parameters:
129 | /// - rows: number of rows
130 | /// - cols: number of columns
131 | /// - v: vector of values
132 | /// - Returns: diagonal matrix with specified values and size
133 | public func diag(_ rows: Int, _ cols: Int, _ v: Vector) -> Matrix {
134 | precondition(rows > 0 && cols > 0, "Matrix dimensions must be positive")
135 | return Matrix((0.. Vector in
136 | var row = Vector(repeating: 0.0, count: cols)
137 | if (i < cols) {
138 | row[i] = v[i]
139 | }
140 | return row
141 | })
142 | }
143 |
144 | // MARK: - Matrix class
145 |
146 | /// Matrix dimensions.
147 | ///
148 | /// - Row: row.
149 | /// - Column: column.
150 | public enum Dim {
151 | case Row
152 | case Column
153 | }
154 |
155 | /// Matrix of Double values
156 | public class Matrix {
157 | public var flat = Vector()
158 | internal var _rows: Int = 0
159 | internal var _cols: Int = 0
160 |
161 | /// Number of rows in Matrix.
162 | public var rows: Int {
163 | return _rows
164 | }
165 |
166 | /// Number of columns in Matrix.
167 | public var cols: Int {
168 | return _cols
169 | }
170 |
171 | /// Transpose
172 | public var T: Matrix {
173 | get {
174 | return transpose(self)
175 | }
176 | }
177 |
178 | public init(_ r: Int, _ c: Int, _ value: Double = 0.0) {
179 | precondition(r > 0 && c > 0, "Matrix dimensions must be positive")
180 | flat = Vector(repeating: value, count: r * c)
181 | _rows = r
182 | _cols = c
183 | }
184 |
185 | public init(_ r: Int, _ c: Int, _ f: Vector) {
186 | precondition(r * c == f.count, "Matrix dimensions must agree")
187 | flat = f
188 | _rows = r
189 | _cols = c
190 | }
191 |
192 | /// Create new Matrix by copying existing.
193 | public init(_ M: Matrix) {
194 | flat = M.flat
195 | _rows = M.rows
196 | _cols = M.cols
197 | }
198 |
199 | /// Create 1-column Matrix (transposed Vector)
200 | public init(_ v: Vector) {
201 | flat = v
202 | _rows = v.count
203 | _cols = 1
204 | }
205 |
206 | /// Create Matrix from array of Vectors (two-dimensional array)
207 | public init(_ data: [Vector]) {
208 | // assuming empty input as invalid
209 | precondition(data.count > 0, "Input must not be empty")
210 | precondition(data[0].count > 0, "Input must not be empty")
211 | // check if all subarrays have same length
212 | precondition(Set(data.map { $0.count }).count == 1, "Input dimensions must agree")
213 |
214 | flat = data.flatMap { $0 }
215 | _rows = data.count
216 | _cols = data[0].count
217 | }
218 | }
219 |
220 | // MARK: - Gathering
221 |
222 | extension Matrix {
223 | /// Get M(row, column) element of Matrix.
224 | ///
225 | /// - Parameters:
226 | /// - row: row position of element (0-based)
227 | /// - col: col position of element (0-based)
228 | public subscript(_ row: Int, _ col: Int ) -> Double {
229 | get {
230 | precondition(indexIsValidForRow(row, col), "Invalid index")
231 | return flat[(row * cols) + col]
232 | }
233 |
234 | set {
235 | precondition(indexIsValidForRow(row, col), "Invalid index")
236 | flat[(row * cols) + col] = newValue
237 | }
238 | }
239 |
240 | /// Get M(index) element of row-major represented Matrix.
241 | ///
242 | /// - Parameters:
243 | /// - index: index of element (0-based, 0 <= index < M.rows * M.cols)
244 | public subscript(_ index: Int) -> Double {
245 | get {
246 | precondition(index < rows * cols, "Invalid index")
247 | return flat[index]
248 | }
249 |
250 | set {
251 | precondition(index < rows * cols, "Invalid index")
252 | flat[index] = newValue
253 | }
254 | }
255 |
256 | /// Get M(row) row of Matrix.
257 | ///
258 | /// - Parameters:
259 | /// - row: row index (0-based)
260 | public subscript(row row: Int) -> Vector {
261 | get {
262 | precondition(row < rows, "Invalid index")
263 | let startIndex = row * cols
264 | let endIndex = row * cols + cols
265 | return Array(flat[startIndex.. Vector {
282 | get {
283 | precondition(col < cols, "Invalid index")
284 | var result = Vector(repeating: 0.0, count: rows)
285 | _ = (0.. () in
286 | let index = i * cols + col
287 | result[i] = flat[index]
288 | }
289 | return result
290 | }
291 |
292 | set {
293 | precondition(col < cols, "Invalid index")
294 | precondition(newValue.count == rows, "Input dimensions must agree")
295 | _ = (0.. () in
296 | let index = i * cols + col
297 | flat[index] = newValue[i]
298 | }
299 | }
300 | }
301 |
302 | /// Get and set M(row, col) submatrix of Matrix.
303 | ///
304 | /// The range-based subscript methods for getting and setting submatricies.
305 | ///
306 | /// var M = Matrix([[1, 2, 3, 4],
307 | /// [5, 6, 7, 8],
308 | /// [9, 10, 11, 12])
309 | ///
310 | /// var K = Matrix([[1, 0],
311 | /// [0, 1])
312 | ///
313 | /// - Using bounded ranges, including partial (e.g. `..<3`):
314 | ///
315 | /// M[1..<3, 0..1] = K
316 | /// // M is now:
317 | /// // [[1, 2, 3, 4],
318 | /// // [1, 0, 7, 8],
319 | /// // [0, 1, 11, 12]]
320 | ///
321 | /// K = M[0...1, 2...]
322 | /// // K is now:
323 | /// // [[3, 4]
324 | /// // [7, 8]]
325 | ///
326 | /// - Using unbounded ranges:
327 | ///
328 | /// K = M[..., 1..2]
329 | /// // K is now:
330 | /// // [[ 2, 3],
331 | /// // [ 6, 7],
332 | /// // [10, 11]]
333 | ///
334 | /// - Parameters:
335 | /// - row: Range for rows (0-based)
336 | /// - col: Range for cols (0-based)
337 | ///
338 | /// - Returns: submatrix of size `row.count` by `col.count`
339 | ///
340 | public subscript(_ row: A, _ col: B) -> Matrix where A.Bound == Int, B.Bound == Int {
341 | get {
342 | return self[ClosedRange(row.relative(to: self[row: 0])), ClosedRange(col.relative(to: self[col: 0]))]
343 | }
344 |
345 | set {
346 | self[ClosedRange(row.relative(to: self[row: 0])), ClosedRange(col.relative(to: self[col: 0]))] = newValue
347 | }
348 | }
349 |
350 | public subscript(_ : UnboundedRange, _ col: B) -> Matrix where B.Bound == Int {
351 | get { return self[0..(col.relative(to: self[col: 0]))] }
352 | set { self[0..(col.relative(to: self[col: 0]))] = newValue }
353 | }
354 |
355 | public subscript(_ row: A, _ : UnboundedRange) -> Matrix where A.Bound == Int {
356 | get { return self[ClosedRange(row.relative(to: self[row: 0])), 0..(row.relative(to: self[row: 0])), 0.. Matrix {
361 | get { return self}
362 | set { self[0.. Matrix {
390 | get { return self[row..., col...]}
391 | set { self[row..<(row + newValue.rows), col..<(col + newValue.cols)] = newValue}
392 | }
393 |
394 | public subscript(_ row: ClosedRange, _ col: ClosedRange) -> Matrix {
395 | get {
396 | precondition(indexIsValidForRow(row.lowerBound, col.lowerBound), "Invalid range")
397 | precondition(indexIsValidForRow(row.upperBound, col.upperBound), "Invalid range")
398 |
399 | let dst = Matrix(row.count, col.count)
400 |
401 | flat.withUnsafeBufferPointer { srcBuf in
402 | let srcPtr = srcBuf.baseAddress! + row.lowerBound * cols + col.lowerBound
403 | vDSP_mmovD(srcPtr, &dst.flat,
404 | vDSP_Length(col.count), vDSP_Length(row.count),
405 | vDSP_Length(cols), vDSP_Length(col.count))
406 | }
407 |
408 | return dst
409 | }
410 |
411 | set {
412 | precondition(indexIsValidForRow(row.lowerBound, col.lowerBound), "Invalid range")
413 | precondition(indexIsValidForRow(row.upperBound, col.upperBound), "Invalid range")
414 | precondition(newValue.cols == col.count && newValue.rows == row.count, "Matrix dimensions must agree")
415 |
416 | flat.withUnsafeMutableBufferPointer { dstBuf in
417 | let dstPtr = dstBuf.baseAddress! + row.lowerBound * cols + col.lowerBound
418 | vDSP_mmovD(newValue.flat, dstPtr,
419 | vDSP_Length(col.count), vDSP_Length(row.count),
420 | vDSP_Length(newValue.cols), vDSP_Length(cols))
421 | }
422 | }
423 | }
424 |
425 | /// Construct new matrix from source using specified extractor.
426 | ///
427 | /// Alternatively, `m[e]` can be executed with `m ?? e` or `slice(m, e)`
428 | ///
429 | /// - Parameters
430 | /// - e: extractor tuple for rows and columns
431 | /// - Returns: extracted matrix
432 | public subscript(_ e: (er: Extractor, ec: Extractor)) -> Matrix {
433 | return slice(self, e)
434 | }
435 |
436 | internal func indexIsValidForRow(_ row: Int, _ col: Int) -> Bool {
437 | return row >= 0 && row < rows && col >= 0 && col < cols
438 | }
439 | }
440 |
441 | public func toRows(_ A: Matrix, _ d: Dim) -> Matrix {
442 | switch d {
443 | case .Row:
444 | return A
445 | case .Column:
446 | return transpose(A)
447 | }
448 | }
449 |
450 | public func toCols(_ A: Matrix, _ d: Dim) -> Matrix {
451 | switch d {
452 | case .Row:
453 | return transpose(A)
454 | case .Column:
455 | return A
456 | }
457 | }
458 |
459 | // MARK: - Matrix manipulation
460 |
461 | /// Vertically stack (top-to-bottom) rows in matrices.
462 | ///
463 | /// Precondition: All matrices need the same number of columns.
464 | ///
465 | /// - Parameters:
466 | /// - ma: [Matrix] (array of matrix)
467 | /// - Returns: new matrix by vertically stacking rows of input matrices
468 | public func vstack(_ ma: [Matrix]) -> Matrix {
469 | precondition(ma.count > 0, "Must have at least 1 input matrix in array")
470 | var m = ma[0]
471 | for i in 1.. Matrix {
486 | precondition(ma.count > 0, "Must have at least 1 input matrix in array")
487 | var m = ma[0]
488 | for i in 1.. Matrix {
503 | return insert(m, rows: Matrix([row]), at: index)
504 | }
505 |
506 | /// Insert rows to matrix at specified position.
507 | ///
508 | /// - Parameters:
509 | /// - m: matrix
510 | /// - rows: rows values to insert represented as matrix
511 | /// - at: index to insert rows to
512 | /// - Returns: new matrix with inserted rows
513 | public func insert(_ m: Matrix, rows: Matrix, at index: Int) -> Matrix {
514 | precondition(rows.cols == m.cols, "Input dimensions must agree")
515 | precondition(index <= m.rows, "Index out of bounds")
516 |
517 | let res = zeros(m.rows + rows.rows, m.cols)
518 |
519 | if (index > 0) {
520 | vDSP_mmovD(m.flat, &res.flat, vDSP_Length(m.cols), vDSP_Length(index), vDSP_Length(m.cols), vDSP_Length(res.cols))
521 | }
522 |
523 | vDSP_mmovD(rows.flat, &res.flat[index * res.cols], vDSP_Length(m.cols), vDSP_Length(rows.rows), vDSP_Length(m.cols), vDSP_Length(res.cols))
524 |
525 | if (index < m.rows) {
526 | m.flat.withUnsafeBufferPointer { bufPtr in
527 | let p = bufPtr.baseAddress! + index * m.cols
528 | vDSP_mmovD(p, &res.flat[(index + rows.rows) * res.cols], vDSP_Length(m.cols), vDSP_Length(m.rows - index), vDSP_Length(m.cols), vDSP_Length(res.cols))
529 | }
530 | }
531 |
532 | return res
533 | }
534 |
535 | /// Append row to matrix.
536 | ///
537 | /// - Parameters:
538 | /// - m: matrix
539 | /// - row: row values to append represented as row matrix
540 | /// - Returns: new matrix with appended row
541 | public func append(_ m: Matrix, row: Matrix) -> Matrix {
542 | precondition(row.cols == m.cols && row.rows == 1, "Input dimensions must agree")
543 | return insert(m, row: row.flat, at: m.rows)
544 | }
545 |
546 | /// Append row to matrix.
547 | ///
548 | /// Alternatively, `append(m, row: row)` can be executed with `m === row`.
549 | ///
550 | /// - Parameters:
551 | /// - m: matrix
552 | /// - row: row values to append
553 | /// - Returns: new matrix with appended row
554 | public func append(_ m: Matrix, row: Vector) -> Matrix {
555 | let r = Matrix([row])
556 | return append(m, row: r)
557 | }
558 |
559 | /// Append row to matrix constructed from scalar value.
560 | ///
561 | /// Alternatively, `append(m, row: row)` can be executed with `m === row`.
562 | ///
563 | /// - Parameters:
564 | /// - m: matrix
565 | /// - row: row value to append
566 | /// - Returns: new matrix with appended row
567 | public func append(_ m: Matrix, row: Double) -> Matrix {
568 | let r = Vector(repeating: row, count: m.cols)
569 | return append(m, row: r)
570 | }
571 |
572 | /// Append rows to matrix.
573 | ///
574 | /// Alternatively, `append(m, rows: rows)` can be executed with `m === rows`.
575 | ///
576 | /// - Parameters:
577 | /// - m: matrix
578 | /// - rows: rows values to append represented as matrix
579 | /// - Returns: new matrix with appended rows
580 | public func append(_ m: Matrix, rows: Matrix) -> Matrix {
581 | return insert(m, rows: rows, at: m.rows)
582 | }
583 |
584 | /// Append rows to matrix.
585 | ///
586 | /// - Parameters:
587 | /// - m: matrix
588 | /// - rows: rows values to append represented as array of vectors
589 | /// - Returns: new matrix with appended rows
590 | public func append(_ m: Matrix, rows: [Vector]) -> Matrix {
591 | return append(m, rows: Matrix(rows))
592 | }
593 |
594 | /// Append row to matrix constructed from scalar value.
595 | ///
596 | /// Alternatively, `m === row` can be executed with `append(m, row: row)`.
597 | ///
598 | /// - Parameters:
599 | /// - m: matrix
600 | /// - row: row value to append
601 | /// - Returns: new matrix with appended row
602 | public func === (_ m: Matrix, _ row: Double) -> Matrix {
603 | return append(m, row: row)
604 | }
605 |
606 | /// Append row to matrix.
607 | ///
608 | /// Alternatively, `m === row` can be executed with `append(m, row: row)`.
609 | ///
610 | /// - Parameters:
611 | /// - m: matrix
612 | /// - row: row values to append
613 | /// - Returns: new matrix with appended row
614 | public func === (_ m: Matrix, _ row: Vector) -> Matrix {
615 | return append(m, row: row)
616 | }
617 |
618 | /// Prepend row to matrix.
619 | ///
620 | /// - Parameters:
621 | /// - m: matrix
622 | /// - row: row values to prepend represented as row matrix
623 | /// - Returns: new matrix with prepended row
624 | public func prepend(_ m: Matrix, row: Matrix) -> Matrix {
625 | precondition(row.cols == m.cols && row.rows == 1, "Input dimensions must agree")
626 | return insert(m, row: row.flat, at: 0)
627 | }
628 |
629 | /// Prepend row to matrix.
630 | ///
631 | /// Alternatively, `prepend(m, row: row)` can be executed with `row === m`.
632 | ///
633 | /// - Parameters:
634 | /// - m: matrix
635 | /// - row: row values to prepend
636 | /// - Returns: new matrix with prepended row
637 | public func prepend(_ m: Matrix, row: Vector) -> Matrix {
638 | let r = Matrix([row])
639 | return prepend(m, row: r)
640 | }
641 |
642 | /// Prepend row to matrix constructed from scalar value.
643 | ///
644 | /// Alternatively, `prepend(m, row: row)` can be executed with `row === m`.
645 | ///
646 | /// - Parameters:
647 | /// - m: matrix
648 | /// - row: row value to prepend
649 | /// - Returns: new matrix with prepended row
650 | public func prepend(_ m: Matrix, row: Double) -> Matrix {
651 | let r = Vector(repeating: row, count: m.cols)
652 | return prepend(m, row: r)
653 | }
654 |
655 | /// Prepend rows to matrix.
656 | ///
657 | /// Alternatively, `prepend(m, rows: rows)` can be executed with `rows === m`.
658 | ///
659 | /// - Parameters:
660 | /// - m: matrix
661 | /// - rows: rows values to prepend represented as matrix
662 | /// - Returns: new matrix with prepended rows
663 | public func prepend(_ m: Matrix, rows: Matrix) -> Matrix {
664 | return insert(m, rows: rows, at: 0)
665 | }
666 |
667 | /// Prepend rows to matrix.
668 | ///
669 | /// - Parameters:
670 | /// - m: matrix
671 | /// - rows: rows values to prepended represented as array of vectors
672 | /// - Returns: new matrix with prepended rows
673 | public func prepend(_ m: Matrix, rows: [Vector]) -> Matrix {
674 | return prepend(m, rows: Matrix(rows))
675 | }
676 |
677 | /// Prepend row to matrix constructed from scalar value.
678 | ///
679 | /// Alternatively, `row === m` can be executed with `prepend(m, row: row)`.
680 | ///
681 | /// - Parameters:
682 | /// - row: row value to prepend
683 | /// - m: matrix
684 | /// - Returns: new matrix with prepended row
685 | public func === (_ row: Double, _ m: Matrix) -> Matrix {
686 | return prepend(m, row: row)
687 | }
688 |
689 | /// Prepend row to matrix.
690 | ///
691 | /// Alternatively, `row === m` can be executed with `prepend(m, row: row)`.
692 | ///
693 | /// - Parameters:
694 | /// - row: row values to prepend
695 | /// - m: matrix
696 | /// - Returns: new matrix with prepended row
697 | public func === (_ row: Vector, _ m: Matrix) -> Matrix {
698 | return prepend(m, row: row)
699 | }
700 |
701 | /// Horizontally concatenate two matrices.
702 | /// It is similar to appending rhs as rows to lhs
703 | ///
704 | /// Alternatively, `lhs === rhs` can be executed with `append(lhs, rows: rhs)`.
705 | public func === (_ lhs: Matrix, _ rhs: Matrix) -> Matrix {
706 | return append(lhs, rows: rhs)
707 | }
708 |
709 | /// Insert column to matrix at specified position.
710 | ///
711 | /// - Parameters:
712 | /// - m: matrix
713 | /// - cols: column values to insert
714 | /// - at: index to insert column to
715 | /// - Returns: new matrix with inserted column
716 | public func insert(_ m: Matrix, col: Vector, at index: Int) -> Matrix {
717 | return insert(m, cols: Matrix(col), at: index)
718 | }
719 |
720 | /// Insert columns to matrix at specified position.
721 | ///
722 | /// - Parameters:
723 | /// - m: matrix
724 | /// - cols: columns values to insert represented as matrix
725 | /// - at: index to insert columns to
726 | /// - Returns: new matrix with inserted columns
727 | public func insert(_ m: Matrix, cols: Matrix, at index: Int) -> Matrix {
728 | precondition(cols.rows == m.rows, "Input dimensions must agree")
729 | precondition(index <= m.cols && index >= 0, "Index out of bounds")
730 |
731 | let res = zeros(m.rows, m.cols + cols.cols)
732 |
733 | if (index > 0) {
734 | vDSP_mmovD(m.flat, &res.flat, vDSP_Length(index), vDSP_Length(m.rows), vDSP_Length(m.cols), vDSP_Length(res.cols))
735 | }
736 |
737 | vDSP_mmovD(cols.flat, &res.flat[index], vDSP_Length(cols.cols), vDSP_Length(m.rows), vDSP_Length(cols.cols), vDSP_Length(res.cols))
738 |
739 | if (index < m.cols) {
740 | m.flat.withUnsafeBufferPointer { bufPtr in
741 | let p = bufPtr.baseAddress! + index
742 | vDSP_mmovD(p, &res.flat[index + cols.cols], vDSP_Length(m.cols - index), vDSP_Length(m.rows), vDSP_Length(m.cols), vDSP_Length(res.cols))
743 | }
744 | }
745 |
746 | return res
747 | }
748 |
749 | /// Append column to matrix.
750 | ///
751 | /// - Parameters:
752 | /// - m: matrix
753 | /// - col: column values to append represented as column matrix
754 | /// - Returns: new matrix with appended column
755 | public func append(_ m: Matrix, col: Matrix) -> Matrix {
756 | precondition(col.rows == m.rows && col.cols == 1, "Input dimensions must agree")
757 | return insert(m, col: col.flat, at: m.cols)
758 | }
759 |
760 | /// Append column to matrix.
761 | ///
762 | /// Alternatively, `append(m, col: col)` can be executed with `m ||| col`.
763 | ///
764 | /// - Parameters:
765 | /// - m: matrix
766 | /// - col: column values to append
767 | /// - Returns: new matrix with appended column
768 | public func append(_ m: Matrix, col: Vector) -> Matrix {
769 | let c = Matrix(col.count, 1, col)
770 | return append(m, col: c)
771 | }
772 |
773 | /// Append column to matrix constructed from scalar value.
774 | ///
775 | /// Alternatively, `append(m, col: col)` can be executed with `m ||| col`.
776 | ///
777 | /// - Parameters:
778 | /// - m: matrix
779 | /// - col: column value to append
780 | /// - Returns: new matrix with appended column
781 | public func append(_ m: Matrix, col: Double) -> Matrix {
782 | let c = Vector(repeating: col, count: m.rows)
783 | return append(m, col: c)
784 | }
785 |
786 | /// Append columns to matrix.
787 | ///
788 | /// Alternatively, `append(m, cols: cols)` can be executed with `m ||| cols`.
789 | ///
790 | /// - Parameters:
791 | /// - m: matrix
792 | /// - cols: columns values to append represented as matrix
793 | /// - Returns: new matrix with appended columns
794 | public func append(_ m: Matrix, cols: Matrix) -> Matrix {
795 | return insert(m, cols: cols, at: m.cols)
796 | }
797 |
798 | /// Append columns to matrix.
799 | ///
800 | /// - Parameters:
801 | /// - m: matrix
802 | /// - cols: columns values to append represented as array of vectors
803 | /// - Returns: new matrix with appended columns
804 | public func append(_ m: Matrix, cols: [Vector]) -> Matrix {
805 | return append(m, cols: transpose(Matrix(cols)))
806 | }
807 |
808 | /// Append column to matrix constructed from scalar value.
809 | ///
810 | /// Alternatively, `m ||| col` can be executed with `append(m, col: col)`.
811 | ///
812 | /// - Parameters:
813 | /// - m: matrix
814 | /// - col: column value to append
815 | /// - Returns: new matrix with appended column
816 | public func ||| (_ m: Matrix, _ col: Double) -> Matrix {
817 | return append(m, col: col)
818 | }
819 |
820 | /// Append column to matrix.
821 | ///
822 | /// Alternatively, `m ||| col` can be executed with `append(m, col: col)`.
823 | ///
824 | /// - Parameters:
825 | /// - m: matrix
826 | /// - col: column values to append
827 | /// - Returns: new matrix with appended column
828 | public func ||| (_ m: Matrix, _ col: Vector) -> Matrix {
829 | return append(m, col: col)
830 | }
831 |
832 | /// Prepend column to matrix.
833 | ///
834 | /// - Parameters:
835 | /// - m: matrix
836 | /// - col: column values to prepend represented as column matrix
837 | /// - Returns: new matrix with prepended column
838 | public func prepend(_ m: Matrix, col: Matrix) -> Matrix {
839 | precondition(col.rows == m.rows && col.cols == 1, "Input dimensions must agree")
840 | return insert(m, col: col.flat, at: 0)
841 | }
842 |
843 | /// Prepend column to matrix.
844 | ///
845 | /// Alternatively, `prepend(m, col: col)` can be executed with `col ||| m`.
846 | ///
847 | /// - Parameters:
848 | /// - m: matrix
849 | /// - col: column values to prepend
850 | /// - Returns: new matrix with prepended column
851 | public func prepend(_ m: Matrix, col: Vector) -> Matrix {
852 | let c = Matrix(col)
853 | return prepend(m, col: c)
854 | }
855 |
856 | /// Prepend column to matrix constructed from scalar value.
857 | ///
858 | /// Alternatively, `prepend(m, col: col)` can be executed with `col ||| m`.
859 | ///
860 | /// - Parameters:
861 | /// - m: matrix
862 | /// - col: column value to prepend
863 | /// - Returns: new matrix with prepended column
864 | public func prepend(_ m: Matrix, col: Double) -> Matrix {
865 | let c = Vector(repeating: col, count: m.rows)
866 | return prepend(m, col: c)
867 | }
868 |
869 | /// Prepend columns to matrix.
870 | ///
871 | /// Alternatively, `prepend(m, cols: cols)` can be executed with `cols ||| m`.
872 | ///
873 | /// - Parameters:
874 | /// - m: matrix
875 | /// - cols: columns values to prepend represented as matrix
876 | /// - Returns: new matrix with prepended columns
877 | public func prepend(_ m: Matrix, cols: Matrix) -> Matrix {
878 | return insert(m, cols: cols, at: 0)
879 | }
880 |
881 | /// Prepend columns to matrix.
882 | ///
883 | /// - Parameters:
884 | /// - m: matrix
885 | /// - cols: columns values to prepended represented as array of vectors
886 | /// - Returns: new matrix with prepended columns
887 | public func prepend(_ m: Matrix, cols: [Vector]) -> Matrix {
888 | return prepend(m, cols: transpose(Matrix(cols)))
889 | }
890 |
891 | /// Prepend column to matrix constructed from scalar value.
892 | ///
893 | /// Alternatively, `col ||| m` can be executed with `prepend(m, col: col)`.
894 | ///
895 | /// - Parameters:
896 | /// - col: column value to prepend
897 | /// - m: matrix
898 | /// - Returns: new matrix with prepended column
899 | public func ||| (_ col: Double, _ m: Matrix) -> Matrix {
900 | return prepend(m, col: col)
901 | }
902 |
903 | /// Prepend column to matrix.
904 | ///
905 | /// Alternatively, `col ||| m` can be executed with `prepend(m, col: col)`.
906 | ///
907 | /// - Parameters:
908 | /// - col: column values to prepend
909 | /// - m: matrix
910 | /// - Returns: new matrix with prepended column
911 | public func ||| (_ col: Vector, _ m: Matrix) -> Matrix {
912 | return prepend(m, col: col)
913 | }
914 |
915 | /// Vertically concatenate two matrices.
916 | /// It is similar to appending rhs as columns to lhs
917 | ///
918 | /// Alternatively, `lhs ||| rhs` can be executed with `append(lhs, cols: rhs)`.
919 | public func ||| (_ lhs: Matrix, _ rhs: Matrix) -> Matrix {
920 | return append(lhs, cols: rhs)
921 | }
922 |
923 | // MARK: - Slicing
924 |
925 | /// Matrix extractor.
926 | ///
927 | /// - All: Take all rows/columns from source matrix.
928 | /// - Range: Take rows/columns from source matrix with indices
929 | /// starting at `from` with `stride` ending at `to`.
930 | /// - Pos: Take rows/columns from source matrix at specified positions
931 | /// - PosCyc: Take rows/columns from source matrix at specified cyclic positions
932 | /// - Take: Take first `n` rows/columns from source matrix
933 | /// - TakeLast: Take last `n` rows/columns from source matrix
934 | /// - Drop: Drop first `n` rows/columns from source matrix
935 | /// - DropLast: Drop last `n` rows/columns from source matrix
936 | public enum Extractor {
937 | case All
938 | case Range(Int, Int, Int)
939 | case Pos([Int])
940 | case PosCyc([Int])
941 | case Take(Int)
942 | case TakeLast(Int)
943 | case Drop(Int)
944 | case DropLast(Int)
945 | }
946 |
947 | /// Construct new matrix from source using specified extractor
948 | ///
949 | /// Alternatively, `slice(m, e)` can be executed with `m ?? e` or `m[e]`.
950 | ///
951 | /// - Parameters
952 | /// - m: source matrix
953 | /// - e: extractor tuple for rows and columns
954 | /// - Returns: extracted matrix
955 | public func slice(_ m: Matrix, _ e: (er: Extractor, ec: Extractor)) -> Matrix {
956 | switch e {
957 |
958 | case (.All, .All):
959 | return m
960 |
961 | case (.Range(let f, _, let t), _) where f < 0 || t >= m.rows,
962 | (_, .Range(let f, _, let t)) where f < 0 || t >= m.cols,
963 | (.Range(let f, _, let t), _) where f >= m.rows || t < 0,
964 | (_, .Range(let f, _, let t)) where f >= m.cols || t < 0:
965 | preconditionFailure("Range out of bounds")
966 |
967 | case (.Take(let n), _) where n < 0 || n >= m.rows,
968 | (_, .Take(let n)) where n < 0 || n >= m.cols,
969 | (.Drop(let n), _) where n < 0 || n >= m.rows,
970 | (_, .Drop(let n)) where n < 0 || n >= m.cols:
971 | preconditionFailure("Range out of bounds")
972 |
973 | case (.All, _):
974 | return slice(m, (.Pos([Int](0.. 0 && pr.filter { $0 < 0 || $0 > m.rows }.count == 0, "Range out of bounds")
1010 | precondition(pc.count > 0 && pc.filter { $0 < 0 || $0 > m.cols }.count == 0, "Range out of bounds")
1011 | return slice(m, pr, pc)
1012 |
1013 | default:
1014 | preconditionFailure("Invalid range")
1015 | }
1016 | }
1017 |
1018 | func slice(_ m: Matrix, _ rr: [Int], _ cr: [Int]) -> Matrix {
1019 | let res = zeros(rr.count, cr.count)
1020 |
1021 | // vgathrD is using 1-based indices
1022 | let _cr = cr.map { vDSP_Length($0 + 1) }
1023 |
1024 | _ = zip(rr, (0.. () in
1025 | var row = zeros(res.cols)
1026 | m.flat.withUnsafeBufferPointer { bufPtr in
1027 | let p = bufPtr.baseAddress! + i * m.cols
1028 | vDSP_vgathrD(p, _cr, 1, &row, 1, vDSP_Length(res.cols))
1029 | }
1030 | res.flat.withUnsafeMutableBufferPointer { bufPtr in
1031 | let p = bufPtr.baseAddress! + j * res.cols
1032 | vDSP_mmovD(row, p, vDSP_Length(res.cols), vDSP_Length(1), vDSP_Length(res.cols), vDSP_Length(res.cols))
1033 | }
1034 | }
1035 |
1036 | return res
1037 | }
1038 |
1039 | /// Construct new matrix from source using specified extractor.
1040 | ///
1041 | /// Alternatively, `m ?? e` can be executed with `slice(m, e)` or `m[e]`.
1042 | ///
1043 | /// - Parameters
1044 | /// - m: source matrix
1045 | /// - e: extractor tuple for rows and columns
1046 | /// - Returns: extracted matrix
1047 | public func ?? (_ m: Matrix, _ e: (er: Extractor, ec: Extractor)) -> Matrix {
1048 | return slice(m, e)
1049 | }
1050 |
1051 | // MARK: - Map-reduce
1052 |
1053 | /// Map all elements of source matrix to new matrix using specified function.
1054 | ///
1055 | /// - Parameters
1056 | /// - A: source matrix
1057 | /// - f: mapping function
1058 | /// - Returns: mapped matrix
1059 | public func map(_ A: Matrix, _ f: ((Double) -> Double)) -> Matrix {
1060 | return Matrix(A.rows, A.cols, A.flat.map(f))
1061 | }
1062 |
1063 | /// Map all elements of source matrix to new matrix using specified function
1064 | /// which operates on vectors.
1065 | ///
1066 | /// - Parameters
1067 | /// - A: source matrix
1068 | /// - f: mapping function
1069 | /// - Returns: mapped matrix
1070 | public func map(_ A: Matrix, _ f: ((Vector) -> Vector)) -> Matrix {
1071 | return matrixFunction(f, A)
1072 | }
1073 |
1074 | /// Perform reduce operation on a matrix using specified function
1075 | /// within the specified dimension.
1076 | ///
1077 | /// - Parameters
1078 | /// - A: source matrix
1079 | /// - f: reducing function
1080 | /// - d: dimesion to apply reduce within (Row by default)
1081 | /// - Returns: vector of reduced values
1082 | public func reduce(_ A: Matrix, _ f: ((Vector) -> Double), _ d: Dim = .Row) -> Vector {
1083 | return aggMatrixFunction(f, A, d)
1084 | }
1085 |
1086 | // MARK: - Sequence
1087 |
1088 | extension Matrix: Sequence {
1089 | public typealias MatrixIterator = AnyIterator>
1090 | /// Iterate through matrix by rows
1091 | public func makeIterator() -> MatrixIterator {
1092 | let end = rows * cols
1093 | var nextRowStart = 0
1094 |
1095 | return AnyIterator {
1096 | if nextRowStart == end {
1097 | return nil
1098 | }
1099 |
1100 | let currentRowStart = nextRowStart
1101 | nextRowStart += self.cols
1102 |
1103 | return self.flat[currentRowStart.. Bool {
1122 | return lhs.rows == rhs.rows && lhs.cols == rhs.cols && lhs.flat ==~ rhs.flat
1123 | }
1124 |
1125 | /// Check if two matrices are not equal using Double value approximate comparison
1126 | public func != (lhs: Matrix, rhs: Matrix) -> Bool {
1127 | return lhs.rows != rhs.rows || lhs.cols != rhs.cols || lhs.flat !=~ rhs.flat
1128 | }
1129 |
1130 | extension Matrix: Comparable {}
1131 |
1132 | /// Check if one matrix is greater than another using Double value approximate comparison
1133 | public func > (lhs: Matrix, rhs: Matrix) -> Bool {
1134 | return lhs.rows == rhs.rows && lhs.cols == rhs.cols && lhs.flat >~ rhs.flat
1135 | }
1136 |
1137 | /// Check if one matrix is less than another using Double value approximate comparison
1138 | public func < (lhs: Matrix, rhs: Matrix) -> Bool {
1139 | return lhs.rows == rhs.rows && lhs.cols == rhs.cols && lhs.flat <~ rhs.flat
1140 | }
1141 |
1142 | /// Check if one matrix is greater than or equal to another using Double value approximate comparison
1143 | public func >= (lhs: Matrix, rhs: Matrix) -> Bool {
1144 | return lhs.rows == rhs.rows && lhs.cols == rhs.cols && lhs.flat >=~ rhs.flat
1145 | }
1146 |
1147 | /// Check if one matrix is less than or equal to another using Double value approximate comparison
1148 | public func <= (lhs: Matrix, rhs: Matrix) -> Bool {
1149 | return lhs.rows == rhs.rows && lhs.cols == rhs.cols && lhs.flat <=~ rhs.flat
1150 | }
1151 |
--------------------------------------------------------------------------------
/Sources/MatrixAlgebra.swift:
--------------------------------------------------------------------------------
1 | // MatrixAlgebra.swift
2 | //
3 | // Copyright (c) 2017 Alexander Taraymovich
4 | // All rights reserved.
5 | //
6 | // This software may be modified and distributed under the terms
7 | // of the BSD license. See the LICENSE file for details.
8 |
9 | import Accelerate
10 |
11 | /// Matrix triangular part.
12 | ///
13 | /// - Upper: Upper triangular part.
14 | /// - Lower: Lower triangular part.
15 | public enum Triangle {
16 | case Upper
17 | case Lower
18 | }
19 |
20 | // MARK: - Linear algebra operations on matrices
21 |
22 | /// Compute the trace of a matrix.
23 | ///
24 | /// - Parameters:
25 | /// - A: matrix to compute trace of
26 | /// - Returns: sum of the elements on the main diagonal
27 | public func trace(_ A: Matrix) -> Double {
28 | precondition(A.rows == A.cols, "Matrix dimensions must agree")
29 | return sum((0.. Matrix {
40 | let C: Matrix = zeros(A.cols, A.rows)
41 | vDSP_mtransD(A.flat, 1, &(C.flat), 1, vDSP_Length(A.cols), vDSP_Length(A.rows))
42 | return C
43 | }
44 |
45 | /// Transpose matrix.
46 | ///
47 | /// Alternatively, `A′` can be executed with `transpose(A)`.
48 | ///
49 | /// - Parameters
50 | /// - A: matrix
51 | /// - Returns: transposed matrix
52 | public postfix func ′ (_ a: Matrix) -> Matrix {
53 | return transpose(a)
54 | }
55 |
56 | /// Perform matrix multiplication.
57 | ///
58 | /// Alternatively, `mtimes(A, B)` can be executed with `A * B`.
59 | ///
60 | /// - Parameters
61 | /// - A: left matrix
62 | /// - B: right matrix
63 | /// - Returns: matrix product of A and B
64 | public func mtimes(_ A: Matrix, _ B: Matrix) -> Matrix {
65 | precondition(A.cols == B.rows, "Matrix dimensions must agree")
66 | let C: Matrix = zeros(A.rows, B.cols)
67 | vDSP_mmulD(A.flat, 1, B.flat, 1, &(C.flat), 1, vDSP_Length(A.rows), vDSP_Length(B.cols), vDSP_Length(A.cols))
68 | return C
69 | }
70 |
71 | /// Perform matrix multiplication.
72 | ///
73 | /// Alternatively, `A * B` can be executed with `mtimes(A, B)`.
74 | ///
75 | /// - Parameters
76 | /// - A: left matrix
77 | /// - B: right matrix
78 | /// - Returns: matrix product of A and B
79 | public func * (_ A: Matrix, _ B: Matrix) -> Matrix {
80 | return mtimes(A, B)
81 | }
82 |
83 | /// Raise matrix to specified power (integer value).
84 | ///
85 | /// If power is 1, source matrix is returned
86 | /// If power is -1, inverted matrix is returned
87 | /// If power is > 1, continuous matrix product result is returned (eg `mpower(A, 2) = mtimes(A, A)`)
88 | /// If power is < -1, continuous matrix product of inverted matrix result is returned
89 | /// All other values are invalid
90 | ///
91 | /// Alternatively, `mpower(A, p)` can be executed with `A ^ p`.
92 | ///
93 | /// - Parameters
94 | /// - A: matrix
95 | /// - p: power to raise matrix to (integer)
96 | /// - Returns: matrix A raised to power p
97 | public func mpower(_ A: Matrix, _ p: Int) -> Matrix {
98 | precondition(A.cols == A.rows, "Matrix dimensions must agree")
99 | switch p {
100 | case 1:
101 | return Matrix(A)
102 | case -1:
103 | return inv(A)
104 | case _ where p > 1:
105 | var C = Matrix(A)
106 | var p = p
107 | while (p > 1) {
108 | C = mtimes(A, C)
109 | p -= 1
110 | }
111 | return C
112 | case _ where p < -1:
113 | return inv(mpower(A, -p))
114 | default:
115 | return eye(A.rows, A.cols)
116 | }
117 | }
118 |
119 | /// Raise matrix to specified power (integer value).
120 | ///
121 | /// If power is 1, source matrix is returned
122 | /// If power is -1, inverted matrix is returned
123 | /// If power is > 1, continuous matrix product result is returned (eg `A ^ 2 = mtimes(A, A)`)
124 | /// If power is < -1, continuous matrix product of inverted matrix result is returned
125 | /// All other values are invalid
126 | ///
127 | /// Alternatively, `A ^ p` can be executed with `mpower(A, p)`.
128 | ///
129 | /// - Parameters
130 | /// - A: matrix
131 | /// - p: power to raise matrix to (integer)
132 | /// - Returns: matrix A raised to power p
133 | public func ^ (_ a: Matrix, _ p: Int) -> Matrix {
134 | return mpower(a, p)
135 | }
136 |
137 | /// Compute the inverse of a given square matrix.
138 | ///
139 | /// A precondition error is thrown if the given matrix is singular or algorithm fails to converge.
140 | ///
141 | /// - Parameters:
142 | /// - A: square matrix to invert
143 | /// - Returns: inverse of A matrix
144 | public func inv(_ A: Matrix) -> Matrix {
145 | precondition(A.rows == A.cols, "Matrix dimensions must agree")
146 | let B = Matrix(A)
147 |
148 | var M = __CLPK_integer(A.rows)
149 | var N = M
150 | var LDA = N
151 | var pivot = [__CLPK_integer](repeating: 0, count: Int(N))
152 |
153 | var wkOpt = __CLPK_doublereal(0.0)
154 | var lWork = __CLPK_integer(-1)
155 |
156 | var error: __CLPK_integer = 0
157 |
158 | dgetrf_(&M, &N, &(B.flat), &LDA, &pivot, &error)
159 |
160 | precondition(error == 0, "Matrix is non invertible")
161 |
162 | /* Query and allocate the optimal workspace */
163 |
164 | dgetri_(&N, &(B.flat), &LDA, &pivot, &wkOpt, &lWork, &error)
165 |
166 | lWork = __CLPK_integer(wkOpt)
167 | var work = Vector(repeating: 0.0, count: Int(lWork))
168 |
169 | /* Compute inversed matrix */
170 |
171 | dgetri_(&N, &(B.flat), &LDA, &pivot, &work, &lWork, &error)
172 |
173 | precondition(error == 0, "Matrix is non invertible")
174 |
175 | return B
176 | }
177 |
178 | /// Compute eigen values and vectors of a given square matrix.
179 | ///
180 | /// A precondition error is thrown if the algorithm fails to converge.
181 | ///
182 | /// - Parameters:
183 | /// - A: square matrix to calculate eigen values and vectors of
184 | /// - Returns: eigenvectors matrix (by rows) and diagonal matrix with eigenvalues on the main diagonal
185 | public func eig(_ A: Matrix) -> (V: Matrix, D: Matrix) {
186 | precondition(A.rows == A.cols, "Matrix dimensions must agree")
187 |
188 | let V = Matrix(A)
189 |
190 | var N = __CLPK_integer(A.rows)
191 |
192 | var LDA = N
193 |
194 | var wkOpt = __CLPK_doublereal(0.0)
195 | var lWork = __CLPK_integer(-1)
196 |
197 | var jobvl: Int8 = 86 // 'V'
198 | var jobvr: Int8 = 86 // 'V'
199 |
200 | var error = __CLPK_integer(0)
201 |
202 | // Real parts of eigenvalues
203 | var wr = Vector(repeating: 0.0, count: Int(N))
204 | // Imaginary parts of eigenvalues
205 | var wi = Vector(repeating: 0.0, count: Int(N))
206 | // Left eigenvectors
207 | var vl = [__CLPK_doublereal](repeating: 0.0, count: Int(N * N))
208 | // Right eigenvectors
209 | var vr = [__CLPK_doublereal](repeating: 0.0, count: Int(N * N))
210 |
211 | var ldvl = N
212 | var ldvr = N
213 |
214 | /* Query and allocate the optimal workspace */
215 |
216 | dgeev_(&jobvl, &jobvr, &N, &V.flat, &LDA, &wr, &wi, &vl, &ldvl, &vr, &ldvr, &wkOpt, &lWork, &error)
217 |
218 | lWork = __CLPK_integer(wkOpt)
219 | var work = Vector(repeating: 0.0, count: Int(lWork))
220 |
221 | /* Compute eigen vectors */
222 |
223 | dgeev_(&jobvl, &jobvr, &N, &V.flat, &LDA, &wr, &wi, &vl, &ldvl, &vr, &ldvr, &work, &lWork, &error)
224 |
225 | precondition(error == 0, "Failed to compute eigen vectors")
226 |
227 | return (toRows(Matrix(A.rows, A.cols, vl), .Column), diag(wr))
228 | }
229 |
230 | /// Perform a singular value decomposition of a given matrix.
231 | ///
232 | /// - Parameters:
233 | /// - A: matrix to find singular values of
234 | /// - Returns: matrices U, S, and V such that `A = U * S * transpose(V)`
235 | public func svd(_ A: Matrix) -> (U: Matrix, S: Matrix, V: Matrix) {
236 | /* LAPACK is using column-major order */
237 | let _A = toCols(A, .Row)
238 |
239 | var jobz: Int8 = 65 // 'A'
240 |
241 | var M = __CLPK_integer(A.rows);
242 | var N = __CLPK_integer(A.cols);
243 |
244 | var LDA = M;
245 | var LDU = M;
246 | var LDVT = N;
247 |
248 | var wkOpt = __CLPK_doublereal(0.0)
249 | var lWork = __CLPK_integer(-1)
250 | var iWork = [__CLPK_integer](repeating: 0, count: Int(8 * min(M, N)))
251 |
252 | var error = __CLPK_integer(0)
253 |
254 | var s = Vector(repeating: 0.0, count: Int(min(M, N)))
255 | let U = Matrix(Int(LDU), Int(M))
256 | let VT = Matrix(Int(LDVT), Int(N))
257 |
258 | /* Query and allocate the optimal workspace */
259 | dgesdd_(&jobz, &M, &N, &_A.flat, &LDA, &s, &U.flat, &LDU, &VT.flat, &LDVT, &wkOpt, &lWork, &iWork, &error)
260 |
261 | lWork = __CLPK_integer(wkOpt)
262 | var work = Vector(repeating: 0.0, count: Int(lWork))
263 |
264 | /* Compute SVD */
265 | dgesdd_(&jobz, &M, &N, &_A.flat, &LDA, &s, &U.flat, &LDU, &VT.flat, &LDVT, &work, &lWork, &iWork, &error)
266 |
267 | precondition(error == 0, "Failed to compute SVD")
268 |
269 | return (toRows(U, .Column), diag(Int(M), Int(N), s), VT)
270 | }
271 |
272 | /// Perform a generalized singular value decomposition of 2 given matrices.
273 | ///
274 | /// - Parameters:
275 | /// - A: first matrix
276 | /// - B: second matrix
277 | /// - Returns: matrices U, V, and Q, plus vectors alpha and beta
278 | public func gsvd(_ A: Matrix, _ B: Matrix) -> (U: Matrix, V: Matrix, Q: Matrix, alpha: Vector, beta: Vector, success: Bool) {
279 | /* LAPACK is using column-major order */
280 | let _A = toCols(A, .Row)
281 | let _B = toCols(B, .Row)
282 |
283 | var jobu:Int8 = Int8(Array("U".utf8).first!)
284 | var jobv:Int8 = Int8(Array("V".utf8).first!)
285 | var jobq:Int8 = Int8(Array("Q".utf8).first!)
286 |
287 | var M = __CLPK_integer(A.rows)
288 | var N = __CLPK_integer(A.cols)
289 | var P = __CLPK_integer(B.rows)
290 |
291 | var LDA = M
292 | var LDB = P
293 | var LDU = M
294 | var LDV = P
295 | var LDQ = N
296 |
297 | let lWork = max(max(Int(3*N),Int(M)),Int(P))+Int(N)
298 | var iWork = [__CLPK_integer](repeating: 0, count: Int(N))
299 | var work = Vector(repeating: 0.0, count: Int(lWork) * 4)
300 | var error = __CLPK_integer(0)
301 |
302 | var k = __CLPK_integer()
303 | var l = __CLPK_integer()
304 |
305 | let U = Matrix(Int(LDU), Int(M))
306 | let V = Matrix(Int(LDV), Int(P))
307 | let Q = Matrix(Int(LDQ), Int(N))
308 | var alpha = Vector(repeating: 0.0, count: Int(N))
309 | var beta = Vector(repeating: 0.0, count: Int(N))
310 |
311 | dggsvd_(&jobu, &jobv, &jobq, &M, &N, &P, &k, &l, &_A.flat, &LDA, &_B.flat, &LDB, &alpha, &beta, &U.flat, &LDU, &V.flat, &LDV, &Q.flat, &LDQ, &work, &iWork, &error)
312 |
313 | return (toRows(U, .Column), toRows(V, .Column), toRows(Q, .Column), Vector(alpha[Int(k)...Int(k+l)-1]), Vector(beta[Int(k)...Int(k+l)-1]), error == 0)
314 | }
315 |
316 | /// Compute the Cholesky factorization of a real symmetric positive definite matrix.
317 | ///
318 | /// A precondition error is thrown if the algorithm fails to converge.
319 | ///
320 | /// - Parameters:
321 | /// - A: square matrix to compute Cholesky factorization of
322 | /// - t: Triangle value (.Upper, .Lower)
323 | /// - Returns: upper triangular matrix U so that `A = U' * U` or
324 | /// lower triangular matrix L so that `A = L * L'`
325 | public func chol(_ A: Matrix, _ t: Triangle = .Upper) -> Matrix {
326 | precondition(A.rows == A.cols, "Matrix dimensions must agree")
327 |
328 | var uplo: Int8
329 | switch t {
330 | case .Upper:
331 | uplo = 85 // 'U'
332 | case .Lower:
333 | uplo = 76 // 'L'
334 | }
335 |
336 | var N = __CLPK_integer(A.rows)
337 |
338 | /* LAPACK is using column-major order */
339 | var U = toCols(A, .Row)
340 |
341 | var LDA = N
342 |
343 | var error = __CLPK_integer(0)
344 |
345 | /* Compute Cholesky decomposition */
346 |
347 | dpotrf_(&uplo, &N, &U.flat, &LDA, &error)
348 |
349 | precondition(error == 0, "Failed to compute Cholesky decomposition")
350 |
351 | U = toRows(U, .Column)
352 |
353 | return tri(U, t)
354 | }
355 |
356 | /// Return the upper/lower triangular part of a given matrix.
357 | ///
358 | /// - Parameters:
359 | /// - A: matrix
360 | /// - t: Triangle value (.Upper, .Lower)
361 | /// - Returns: upper/lower triangular part
362 | public func tri(_ A: Matrix, _ t: Triangle) -> Matrix {
363 | let _A = zeros(A.rows, A.cols)
364 | switch t {
365 | case .Upper:
366 | for i in (0.. Double {
391 | precondition(A.rows == A.cols, "Matrix dimensions must agree")
392 | let B = Matrix(A)
393 |
394 | var M = __CLPK_integer(A.rows)
395 | var N = M
396 | var LDA = N
397 | var pivot = [__CLPK_integer](repeating: 0, count: Int(N))
398 |
399 | var error: __CLPK_integer = 0
400 |
401 | dgetrf_(&M, &N, &(B.flat), &LDA, &pivot, &error)
402 |
403 | var d = 1.0
404 |
405 | for i in (0.. Matrix {
423 | precondition(A.rows > K.rows && A.cols > K.cols, "The kernel matrix needs to be smaller than the matrix it will convolve.")
424 |
425 | let result: [Double]
426 |
427 | if K.rows == 3 {
428 | result = Accelerate.vDSP.convolve(A.flat, rowCount: A._rows, columnCount: A._cols, with3x3Kernel: K.flat)
429 | } else {
430 | result = Accelerate.vDSP.convolve(A.flat, rowCount: A._rows, columnCount: A._cols, withKernel: K.flat, kernelRowCount: K._rows, kernelColumnCount: K._cols)
431 | }
432 |
433 | return Matrix(A._rows, A._cols, result)
434 | }
435 |
--------------------------------------------------------------------------------
/Sources/MatrixArithmetic.swift:
--------------------------------------------------------------------------------
1 | // MatrixArithmetic.swift
2 | //
3 | // Copyright (c) 2017 Alexander Taraymovich
4 | // All rights reserved.
5 | //
6 | // This software may be modified and distributed under the terms
7 | // of the BSD license. See the LICENSE file for details.
8 |
9 | import Darwin
10 |
11 | // MARK: - Matrix-Matrix arithmetics
12 |
13 | /// Perform matrix addition.
14 | ///
15 | /// Alternatively, `plus(A, B)` can be executed with `A + B`.
16 | ///
17 | /// - Parameters
18 | /// - A: left matrix
19 | /// - B: right matrix
20 | /// - Returns: elementwise matrix sum of A and B
21 | public func plus(_ A: Matrix, _ B: Matrix) -> Matrix {
22 | return matrixMatrixOperation(plus, A, B)
23 | }
24 |
25 | /// Perform matrix addition.
26 | ///
27 | /// Alternatively, `A + B` can be executed with `plus(A, B)`.
28 | ///
29 | /// - Parameters
30 | /// - A: left matrix
31 | /// - B: right matrix
32 | /// - Returns: elementwise matrix sum of A and B
33 | public func + (_ A: Matrix, _ B: Matrix) -> Matrix {
34 | return plus(A, B)
35 | }
36 |
37 | /// Perform matrix substraction.
38 | ///
39 | /// Alternatively, `minus(A, B)` can be executed with `A - B`.
40 | ///
41 | /// - Parameters
42 | /// - A: left matrix
43 | /// - B: right matrix
44 | /// - Returns: elementwise matrix difference of A and B
45 | public func minus(_ A: Matrix, _ B: Matrix) -> Matrix {
46 | return matrixMatrixOperation(minus, A, B)
47 | }
48 |
49 | /// Perform matrix substraction.
50 | ///
51 | /// Alternatively, `A - B` can be executed with `minus(A, B)`.
52 | ///
53 | /// - Parameters
54 | /// - A: left matrix
55 | /// - B: right matrix
56 | /// - Returns: elementwise matrix difference of A and B
57 | public func - (_ A: Matrix, _ B: Matrix) -> Matrix {
58 | return minus(A, B)
59 | }
60 |
61 | /// Perform matrix multiplication.
62 | ///
63 | /// Alternatively, `times(A, B)` can be executed with `A .* B`.
64 | ///
65 | /// - Parameters
66 | /// - A: left matrix
67 | /// - B: right matrix
68 | /// - Returns: elementwise matrix product of A and B
69 | public func times(_ A: Matrix, _ B: Matrix) -> Matrix {
70 | return matrixMatrixOperation(times, A, B)
71 | }
72 |
73 | /// Perform matrix multiplication.
74 | ///
75 | /// Alternatively, `A .* B` can be executed with `times(A, B)`.
76 | ///
77 | /// - Parameters
78 | /// - A: left matrix
79 | /// - B: right matrix
80 | /// - Returns: elementwise matrix product of A and B
81 | public func .* (_ A: Matrix, _ B: Matrix) -> Matrix {
82 | return times(A, B)
83 | }
84 |
85 | /// Perform matrix right division.
86 | ///
87 | /// Alternatively, `rdivide(A, B)` can be executed with `A ./ B`.
88 | ///
89 | /// - Parameters
90 | /// - A: left matrix
91 | /// - B: right matrix
92 | /// - Returns: result of elementwise division of A by B
93 | public func rdivide(_ A: Matrix, _ B: Matrix) -> Matrix {
94 | return matrixMatrixOperation(rdivide, A, B)
95 | }
96 |
97 | /// Perform matrix right division.
98 | ///
99 | /// Alternatively, `A ./ B` can be executed with `rdivide(A, B)`.
100 | ///
101 | /// - Parameters
102 | /// - A: left matrix
103 | /// - B: right matrix
104 | /// - Returns: result of elementwise division of A by B
105 | public func ./ (_ A: Matrix, _ B: Matrix) -> Matrix {
106 | return rdivide(A, B)
107 | }
108 |
109 | /// Perform matrix left division.
110 | ///
111 | /// Alternatively, `ldivide(A, B)` can be executed with `A ./. B`.
112 | ///
113 | /// - Parameters
114 | /// - A: left matrix
115 | /// - B: right matrix
116 | /// - Returns: result of elementwise division of B by A
117 | public func ldivide(_ A: Matrix, _ B: Matrix) -> Matrix {
118 | return matrixMatrixOperation(ldivide, A, B)
119 | }
120 |
121 | /// Perform matrix left division.
122 | ///
123 | /// Alternatively, `A ./. B` can be executed with `ldivide(A, B)`.
124 | ///
125 | /// - Parameters
126 | /// - A: left matrix
127 | /// - B: right matrix
128 | /// - Returns: result of elementwise division of B by A
129 | public func ./. (_ A: Matrix, _ B: Matrix) -> Matrix {
130 | return ldivide(A, B)
131 | }
132 |
133 | // MARK: - Matrix-Scalar arithmetics
134 |
135 | /// Perform matrix and scalar addition.
136 | ///
137 | /// Scalar value expands to matrix dimensions
138 | /// and elementwise matrix addition is performed.
139 | ///
140 | /// Alternatively, `plus(A, b)` can be executed with `A + b`.
141 | ///
142 | /// - Parameters
143 | /// - A: matrix
144 | /// - b: scalar
145 | /// - Returns: elementwise sum of matrix A and scalar b
146 | public func plus(_ A: Matrix, _ b: Double) -> Matrix {
147 | return matrixScalarOperation(plus, A, b)
148 | }
149 |
150 | /// Perform matrix and scalar addition.
151 | ///
152 | /// Scalar value expands to matrix dimensions
153 | /// and elementwise matrix addition is performed.
154 | ///
155 | /// Alternatively, `A + b` can be executed with `plus(A, b)`.
156 | ///
157 | /// - Parameters
158 | /// - A: matrix
159 | /// - b: scalar
160 | /// - Returns: elementwise sum of matrix A and scalar b
161 | public func + (_ A: Matrix, _ b: Double) -> Matrix {
162 | return plus(A, b)
163 | }
164 |
165 | /// Perform scalar and matrix addition.
166 | ///
167 | /// Scalar value expands to matrix dimensions
168 | /// and elementwise matrix addition is performed.
169 | ///
170 | /// Alternatively, `plus(a, B)` can be executed with `a + B`.
171 | ///
172 | /// - Parameters
173 | /// - a: scalar
174 | /// - B: matrix
175 | /// - Returns: elementwise sum of scalar a and matrix B
176 | public func plus(_ a: Double, _ B: Matrix) -> Matrix {
177 | return invMatrixScalarOperation(plus, a, B)
178 | }
179 |
180 | /// Perform scalar and matrix addition.
181 | ///
182 | /// Scalar value expands to matrix dimensions
183 | /// and elementwise matrix addition is performed.
184 | ///
185 | /// Alternatively, `a + B` can be executed with `plus(a, B)`.
186 | ///
187 | /// - Parameters
188 | /// - a: scalar
189 | /// - B: matrix
190 | /// - Returns: elementwise sum of scalar a and matrix B
191 | public func + (_ a: Double, _ B: Matrix) -> Matrix {
192 | return plus(a, B)
193 | }
194 |
195 | /// Perform matrix and scalar substraction.
196 | ///
197 | /// Scalar value expands to matrix dimensions
198 | /// and elementwise matrix substraction is performed.
199 | ///
200 | /// Alternatively, `minus(A, b)` can be executed with `A - b`.
201 | ///
202 | /// - Parameters
203 | /// - A: matrix
204 | /// - b: scalar
205 | /// - Returns: elementwise difference of matrix A and scalar b
206 | public func minus(_ A: Matrix, _ b: Double) -> Matrix {
207 | return matrixScalarOperation(minus, A, b)
208 | }
209 |
210 | /// Perform matrix and scalar substraction.
211 | ///
212 | /// Scalar value expands to matrix dimensions
213 | /// and elementwise matrix substraction is performed.
214 | ///
215 | /// Alternatively, `A - b` can be executed with `minus(A, b)`.
216 | ///
217 | /// - Parameters
218 | /// - A: matrix
219 | /// - b: scalar
220 | /// - Returns: elementwise difference of matrix A and scalar b
221 | public func - (_ A: Matrix, _ b: Double) -> Matrix {
222 | return minus(A, b)
223 | }
224 |
225 | /// Perform scalar and matrix substraction.
226 | ///
227 | /// Scalar value expands to matrix dimensions
228 | /// and elementwise matrix addition is performed.
229 | ///
230 | /// Alternatively, `minus(a, B)` can be executed with `a - B`.
231 | ///
232 | /// - Parameters
233 | /// - a: scalar
234 | /// - B: matrix
235 | /// - Returns: elementwise difference of scalar a and matrix B
236 | public func minus(_ a: Double, _ B: Matrix) -> Matrix {
237 | return invMatrixScalarOperation(minus, a, B)
238 | }
239 |
240 | /// Perform scalar and matrix substraction.
241 | ///
242 | /// Scalar value expands to matrix dimensions
243 | /// and elementwise matrix addition is performed.
244 | ///
245 | /// Alternatively, `a - B` can be executed with `minus(a, B)`.
246 | ///
247 | /// - Parameters
248 | /// - a: scalar
249 | /// - B: matrix
250 | /// - Returns: elementwise difference of scalar a and matrix B
251 | public func - (_ a: Double, _ B: Matrix) -> Matrix {
252 | return minus(a, B)
253 | }
254 |
255 | /// Perform matrix and scalar multiplication.
256 | ///
257 | /// Scalar value expands to matrix dimensions
258 | /// and elementwise matrix multiplication is performed.
259 | ///
260 | /// Alternatively, `times(A, b)` can be executed with `A .* b`.
261 | ///
262 | /// - Parameters
263 | /// - A: matrix
264 | /// - b: scalar
265 | /// - Returns: elementwise product of matrix A and scalar b
266 | public func times(_ A: Matrix, _ b: Double) -> Matrix {
267 | return matrixScalarOperation(times, A, b)
268 | }
269 |
270 | /// Perform matrix and scalar multiplication.
271 | ///
272 | /// Scalar value expands to matrix dimensions
273 | /// and elementwise matrix multiplication is performed.
274 | ///
275 | /// Alternatively, `A .* b` can be executed with `times(A, b)`.
276 | ///
277 | /// - Parameters
278 | /// - A: matrix
279 | /// - b: scalar
280 | /// - Returns: elementwise product of matrix A and scalar b
281 | public func .* (_ A: Matrix, _ b: Double) -> Matrix {
282 | return times(A, b)
283 | }
284 |
285 | /// Perform scalar and matrix multiplication.
286 | ///
287 | /// Scalar value expands to matrix dimensions
288 | /// and elementwise matrix multiplication is performed.
289 | ///
290 | /// Alternatively, `times(a, B)` can be executed with `a .* B`.
291 | ///
292 | /// - Parameters
293 | /// - a: scalar
294 | /// - B: matrix
295 | /// - Returns: elementwise product of scalar a and matrix B
296 | public func times(_ a: Double, _ B: Matrix) -> Matrix {
297 | return invMatrixScalarOperation(times, a, B)
298 | }
299 |
300 | /// Perform scalar and matrix multiplication.
301 | ///
302 | /// Scalar value expands to matrix dimensions
303 | /// and elementwise matrix multiplication is performed.
304 | ///
305 | /// Alternatively, `a .* B` can be executed with `times(a, B)`.
306 | ///
307 | /// - Parameters
308 | /// - a: scalar
309 | /// - B: matrix
310 | /// - Returns: elementwise product of scalar a and matrix B
311 | public func .* (_ a: Double, _ B: Matrix) -> Matrix {
312 | return times(a, B)
313 | }
314 |
315 | /// Perform matrix and scalar right division.
316 | ///
317 | /// Scalar value expands to matrix dimensions
318 | /// and elementwise matrix right division is performed.
319 | ///
320 | /// Alternatively, `rdivide(A, b)` can be executed with `A ./ b`.
321 | ///
322 | /// - Parameters
323 | /// - A: matrix
324 | /// - b: scalar
325 | /// - Returns: result of elementwise division of matrix A by scalar b
326 | public func rdivide(_ A: Matrix, _ b: Double) -> Matrix {
327 | return matrixScalarOperation(rdivide, A, b)
328 | }
329 |
330 | /// Perform matrix and scalar right division.
331 | ///
332 | /// Scalar value expands to matrix dimensions
333 | /// and elementwise matrix right division is performed.
334 | ///
335 | /// Alternatively, `A ./ b` can be executed with `rdivide(A, b)`.
336 | ///
337 | /// - Parameters
338 | /// - A: matrix
339 | /// - b: scalar
340 | /// - Returns: result of elementwise division of matrix A by scalar b
341 | public func ./ (_ A: Matrix, _ b: Double) -> Matrix {
342 | return rdivide(A, b)
343 | }
344 |
345 | /// Perform scalar and matrix right division.
346 | ///
347 | /// Scalar value expands to matrix dimensions
348 | /// and elementwise matrix right division is performed.
349 | ///
350 | /// Alternatively, `rdivide(a, B)` can be executed with `a ./ B`.
351 | ///
352 | /// - Parameters
353 | /// - a: scalar
354 | /// - B: matrix
355 | /// - Returns: result of elementwise division of scalar a by matrix B
356 | public func rdivide(_ a: Double, _ B: Matrix) -> Matrix {
357 | return invMatrixScalarOperation(rdivide, a, B)
358 | }
359 |
360 | /// Perform scalar and matrix right division.
361 | ///
362 | /// Scalar value expands to matrix dimension
363 | /// and elementwise matrix right division is performed.
364 | ///
365 | /// Alternatively, `a ./ B` can be executed with `rdivide(a, B)`.
366 | ///
367 | /// - Parameters
368 | /// - a: scalar
369 | /// - B: matrix
370 | /// - Returns: result of elementwise division of scalar a by matrix B
371 | public func ./ (_ a: Double, _ B: Matrix) -> Matrix {
372 | return rdivide(a, B)
373 | }
374 |
375 | /// Perform matrix and scalar left division.
376 | ///
377 | /// Scalar value expands to matrix dimensions
378 | /// and elementwise matrix left division is performed.
379 | ///
380 | /// Alternatively, `ldivide(A, b)` can be executed with `A ./. b`.
381 | ///
382 | /// - Parameters
383 | /// - A: matrix
384 | /// - b: scalar
385 | /// - Returns: result of elementwise division of scalar b by matrix A
386 | public func ldivide(_ A: Matrix, _ b: Double) -> Matrix {
387 | return matrixScalarOperation(ldivide, A, b)
388 | }
389 |
390 | /// Perform matrix and scalar left division.
391 | ///
392 | /// Scalar value expands to matrix dimensions
393 | /// and elementwise matrix left division is performed.
394 | ///
395 | /// Alternatively, `A ./. b` can be executed with `ldivide(A, b)`.
396 | ///
397 | /// - Parameters
398 | /// - A: matrix
399 | /// - b: scalar
400 | /// - Returns: result of elementwise division of scalar b by matrix aA
401 | public func ./. (_ A: Matrix, _ b: Double) -> Matrix {
402 | return ldivide(A, b)
403 | }
404 |
405 | /// Perform scalar and matrix left division.
406 | ///
407 | /// Scalar value expands to matrix dimensions
408 | /// and elementwise matrix left division is performed.
409 | ///
410 | /// Alternatively, `ldivide(a, B)` can be executed with `a ./. B`.
411 | ///
412 | /// - Parameters
413 | /// - a: scalar
414 | /// - B: matrix
415 | /// - Returns: result of elementwise division of matrix B by scalar a
416 | public func ldivide(_ a: Double, _ B: Matrix) -> Matrix {
417 | return invMatrixScalarOperation(ldivide, a, B)
418 | }
419 |
420 | /// Perform scalar and matrix left division.
421 | ///
422 | /// Scalar value expands to matrix dimensions
423 | /// and elementwise matrix left division is performed.
424 | ///
425 | /// Alternatively, `a ./. B` can be executed with `ldivide(a, B)`.
426 | ///
427 | /// - Parameters
428 | /// - a: scalar
429 | /// - B: matrix
430 | /// - Returns: result of elementwise division of matrix B by scalar a
431 | public func ./. (_ a: Double, _ B: Matrix) -> Matrix {
432 | return ldivide(a, B)
433 | }
434 |
435 | // MARK: - Matrix-Vector arithmetics
436 |
437 | /// Perform matrix and vector addition.
438 | ///
439 | /// Vector value expands to matrix dimensions (by rows)
440 | /// and elementwise matrix addition is performed.
441 | ///
442 | /// Alternatively, `plus(A, b)` can be executed with `A + b`.
443 | ///
444 | /// - Parameters
445 | /// - A: matrix
446 | /// - b: vector
447 | /// - Returns: elementwise sum of matrix A and vector b
448 | public func plus(_ A: Matrix, _ b: Vector) -> Matrix {
449 | return matrixVectorOperation(plus, A, b)
450 | }
451 |
452 | /// Perform matrix and vector addition.
453 | ///
454 | /// Vector value expands to matrix dimensions (by rows)
455 | /// and elementwise matrix addition is performed.
456 | ///
457 | /// Alternatively, `A + b` can be executed with `plus(A, b)`.
458 | ///
459 | /// - Parameters
460 | /// - A: matrix
461 | /// - b: vector
462 | /// - Returns: elementwise sum of matrix A and vector b
463 | public func + (_ A: Matrix, _ b: Vector) -> Matrix {
464 | return plus(A, b)
465 | }
466 |
467 | /// Perform vector and matrix addition.
468 | ///
469 | /// Vector value expands to matrix dimensions (by rows)
470 | /// and elementwise matrix addition is performed.
471 | ///
472 | /// Alternatively, `plus(a, B)` can be executed with `a + B`.
473 | ///
474 | /// - Parameters
475 | /// - a: vector
476 | /// - B: matrix
477 | /// - Returns: elementwise sum of vector a and matrix B
478 | public func plus(_ a: Vector, _ B: Matrix) -> Matrix {
479 | return invMatrixVectorOperation(plus, a, B)
480 | }
481 |
482 | /// Perform vector and matrix addition.
483 | ///
484 | /// Vector value expands to matrix dimensions (by rows)
485 | /// and elementwise matrix addition is performed.
486 | ///
487 | /// Alternatively, `a + B` can be executed with `plus(a, B)`.
488 | ///
489 | /// - Parameters
490 | /// - a: vector
491 | /// - B: matrix
492 | /// - Returns: elementwise sum of vector a and matrix B
493 | public func + (_ a: Vector, _ B: Matrix) -> Matrix {
494 | return plus(a, B)
495 | }
496 |
497 | /// Perform matrix and vector substraction.
498 | ///
499 | /// Vector value expands to matrix dimensions (by rows)
500 | /// and elementwise matrix addition is performed.
501 | ///
502 | /// Alternatively, `minus(A, b)` can be executed with `A - b`.
503 | ///
504 | /// - Parameters
505 | /// - A: matrix
506 | /// - b: vector
507 | /// - Returns: elementwise difference of matrix A and vector b
508 | public func minus(_ A: Matrix, _ b: Vector) -> Matrix {
509 | return matrixVectorOperation(minus, A, b)
510 | }
511 |
512 | /// Perform matrix and vector substraction.
513 | ///
514 | /// Vector value expands to matrix dimensions (by rows)
515 | /// and elementwise matrix addition is performed.
516 | ///
517 | /// Alternatively, `A - b` can be executed with `minus(A, b)`.
518 | ///
519 | /// - Parameters
520 | /// - A: matrix
521 | /// - b: vector
522 | /// - Returns: elementwise difference of matrix A and vector b
523 | public func - (_ A: Matrix, _ b: Vector) -> Matrix {
524 | return minus(A, b)
525 | }
526 |
527 | /// Perform vector and matrix substraction.
528 | ///
529 | /// Vector value expands to matrix dimensions (by rows)
530 | /// and elementwise matrix addition is performed.
531 | ///
532 | /// Alternatively, `minus(a, B)` can be executed with `a - B`.
533 | ///
534 | /// - Parameters
535 | /// - a: vector
536 | /// - B: matrix
537 | /// - Returns: elementwise difference of vector a and matrix B
538 | public func minus(_ a: Vector, _ B: Matrix) -> Matrix {
539 | return invMatrixVectorOperation(minus, a, B)
540 | }
541 |
542 | /// Perform vector and matrix substraction.
543 | ///
544 | /// Vector value expands to matrix dimensions (by rows)
545 | /// and elementwise matrix addition is performed.
546 | ///
547 | /// Alternatively, `a - B` can be executed with `minus(a, B)`.
548 | ///
549 | /// - Parameters
550 | /// - a: vector
551 | /// - B: matrix
552 | /// - Returns: elementwise difference of vector a and matrix B
553 | public func - (_ a: Vector, _ B: Matrix) -> Matrix {
554 | return minus(a, B)
555 | }
556 |
557 | /// Perform matrix and vector multiplication.
558 | ///
559 | /// Vector value expands to matrix dimensions (by rows)
560 | /// and elementwise matrix addition is performed.
561 | ///
562 | /// Alternatively, `times(A, b)` can be executed with `A .* b`.
563 | ///
564 | /// - Parameters
565 | /// - A: matrix
566 | /// - b: vector
567 | /// - Returns: elementwise product of matrix A and vector b
568 | public func times(_ A: Matrix, _ b: Vector) -> Matrix {
569 | return matrixVectorOperation(times, A, b)
570 | }
571 |
572 | /// Perform matrix and vector multiplication.
573 | ///
574 | /// Vector value expands to matrix dimensions (by rows)
575 | /// and elementwise matrix addition is performed.
576 | ///
577 | /// Alternatively, `A .* b` can be executed with `times(A, b)`.
578 | ///
579 | /// - Parameters
580 | /// - A: matrix
581 | /// - b: vector
582 | /// - Returns: elementwise product of matrix A and vector b
583 | public func .* (_ A: Matrix, _ b: Vector) -> Matrix {
584 | return times(A, b)
585 | }
586 |
587 | /// Perform vector and matrix multiplication.
588 | ///
589 | /// Vector value expands to matrix dimensions (by rows)
590 | /// and elementwise matrix addition is performed.
591 | ///
592 | /// Alternatively, `times(a, B)` can be executed with `a .* B`.
593 | ///
594 | /// - Parameters
595 | /// - a: vector
596 | /// - B: matrix
597 | /// - Returns: elementwise product of vector a and matrix B
598 | public func times(_ a: Vector, _ B: Matrix) -> Matrix {
599 | return invMatrixVectorOperation(times, a, B)
600 | }
601 |
602 | /// Perform vector and matrix multiplication.
603 | ///
604 | /// Vector value expands to matrix dimensions (by rows)
605 | /// and elementwise matrix addition is performed.
606 | ///
607 | /// Alternatively, `a .* B` can be executed with `times(a, B)`.
608 | ///
609 | /// - Parameters
610 | /// - a: vector
611 | /// - B: matrix
612 | /// - Returns: elementwise product of vector a and matrix B
613 | public func .* (_ a: Vector, _ B: Matrix) -> Matrix {
614 | return times(a, B)
615 | }
616 |
617 | /// Perform matrix and vector right division.
618 | ///
619 | /// Vector value expands to matrix dimensions (by rows)
620 | /// and elementwise matrix addition is performed.
621 | ///
622 | /// Alternatively, `rdivide(A, b)` can be executed with `A ./ b`.
623 | ///
624 | /// - Parameters
625 | /// - A: matrix
626 | /// - b: vector
627 | /// - Returns: result of elementwise division of matrix A by vector b
628 | public func rdivide(_ A: Matrix, _ b: Vector) -> Matrix {
629 | return matrixVectorOperation(rdivide, A, b)
630 | }
631 |
632 | /// Perform matrix and vector right division.
633 | ///
634 | /// Vector value expands to matrix dimensions (by rows)
635 | /// and elementwise matrix addition is performed.
636 | ///
637 | /// Alternatively, `A ./ b` can be executed with `rdivide(A, b)`.
638 | ///
639 | /// - Parameters
640 | /// - A: matrix
641 | /// - b: vector
642 | /// - Returns: result of elementwise division of matrix A by vector b
643 | public func ./ (_ A: Matrix, _ b: Vector) -> Matrix {
644 | return rdivide(A, b)
645 | }
646 |
647 | /// Perform vector and matrix right division.
648 | ///
649 | /// Vector value expands to matrix dimensions (by rows)
650 | /// and elementwise matrix addition is performed.
651 | ///
652 | /// Alternatively, `rdivide(a, B)` can be executed with `a ./ B`.
653 | ///
654 | /// - Parameters
655 | /// - a: vector
656 | /// - B: matrix
657 | /// - Returns: result of elementwise division of vector a by matrix B
658 | public func rdivide(_ a: Vector, _ B: Matrix) -> Matrix {
659 | return invMatrixVectorOperation(rdivide, a, B)
660 | }
661 |
662 | /// Perform vector and matrix right division.
663 | ///
664 | /// Vector value expands to matrix dimensions (by rows)
665 | /// and elementwise matrix addition is performed.
666 | ///
667 | /// Alternatively, `a ./ B` can be executed with `rdivide(a, B)`.
668 | ///
669 | /// - Parameters
670 | /// - a: vector
671 | /// - B: matrix
672 | /// - Returns: result of elementwise division of vector a by matrix B
673 | public func ./ (_ a: Vector, _ B: Matrix) -> Matrix {
674 | return rdivide(a, B)
675 | }
676 |
677 | /// Perform matrix and vector left division.
678 | ///
679 | /// Vector value expands to matrix dimensions (by rows)
680 | /// and elementwise matrix addition is performed.
681 | ///
682 | /// Alternatively, `ldivide(A, b)` can be executed with `A ./. b`.
683 | ///
684 | /// - Parameters
685 | /// - A: matrix
686 | /// - b: vector
687 | /// - Returns: result of elementwise division of vector b by matrix A
688 | public func ldivide(_ A: Matrix, _ b: Vector) -> Matrix {
689 | return matrixVectorOperation(ldivide, A, b)
690 | }
691 |
692 | /// Perform matrix and vector left division.
693 | ///
694 | /// Vector value expands to matrix dimensions (by rows)
695 | /// and elementwise matrix addition is performed.
696 | ///
697 | /// Alternatively, `A ./. b` can be executed with `ldivide(A, b)`.
698 | ///
699 | /// - Parameters
700 | /// - A: matrix
701 | /// - b: vector
702 | /// - Returns: result of elementwise division of vector b by matrix A
703 | public func ./. (_ A: Matrix, _ b: Vector) -> Matrix {
704 | return ldivide(A, b)
705 | }
706 |
707 | /// Perform vector and matrix left division.
708 | ///
709 | /// Vector value expands to matrix dimensions (by rows)
710 | /// and elementwise matrix addition is performed.
711 | ///
712 | /// Alternatively, `ldivide(a, B)` can be executed with `a ./. B`.
713 | ///
714 | /// - Parameters
715 | /// - a: vector
716 | /// - B: matrix
717 | /// - Returns: result of elementwise division of matrix B by vector a
718 | public func ldivide(_ a: Vector, _ B: Matrix) -> Matrix {
719 | return invMatrixVectorOperation(ldivide, a, B)
720 | }
721 |
722 | /// Perform vector and matrix left division.
723 | ///
724 | /// Vector value expands to matrix dimensions (by rows)
725 | /// and elementwise matrix addition is performed.
726 | ///
727 | /// Alternatively, `a ./. B` can be executed with `ldivide(a, B)`.
728 | ///
729 | /// - Parameters
730 | /// - a: vector
731 | /// - B: matrix
732 | /// - Returns: result of elementwise division of matrix B by vector a
733 | public func ./. (_ a: Vector, _ B: Matrix) -> Matrix {
734 | return ldivide(a, B)
735 | }
736 |
737 | // MARK: - Sign operations on matrix
738 |
739 | /// Absolute value of matrix.
740 | ///
741 | /// - Parameters
742 | /// - A: matrix
743 | /// - Returns: matrix of absolute values of elements of matrix A
744 | public func abs(_ A: Matrix) -> Matrix {
745 | return matrixFunction(abs, A)
746 | }
747 |
748 | /// Negation of matrix.
749 | ///
750 | /// Alternatively, `uminus(A)` can be executed with `-A`.
751 | ///
752 | /// - Parameters
753 | /// - A: matrix
754 | /// - Returns: matrix of negated values of elements of matrix A
755 | public func uminus(_ A: Matrix) -> Matrix {
756 | return matrixFunction(uminus, A)
757 | }
758 |
759 | /// Negation of matrix.
760 | ///
761 | /// Alternatively, `-A` can be executed with `uminus(A)`.
762 | ///
763 | /// - Parameters
764 | /// - A: matrix
765 | /// - Returns: matrix of negated values of elements of matrix A
766 | public prefix func - (_ A: Matrix) -> Matrix {
767 | return uminus(A)
768 | }
769 |
770 | /// Threshold function on matrix.
771 | ///
772 | /// - Parameters
773 | /// - A: matrix
774 | /// - Returns: matrix with values less than certain value set to 0
775 | /// and keeps the value otherwise
776 | public func thr(_ A: Matrix, _ t: Double) -> Matrix {
777 | return Matrix(A.rows, A.cols, thr(A.flat, t))
778 | }
779 |
--------------------------------------------------------------------------------
/Sources/MatrixExponent.swift:
--------------------------------------------------------------------------------
1 | // MatrixExponent.swift
2 | //
3 | // Copyright (c) 2017 Alexander Taraymovich
4 | // All rights reserved.
5 | //
6 | // This software may be modified and distributed under the terms
7 | // of the BSD license. See the LICENSE file for details.
8 |
9 | // MARK: - Power and exponential functions
10 |
11 | /// Exponentiation function, returning matrix raised to power.
12 | ///
13 | /// Alternatively, `power(A, p)` can be executed with `A .^ p`.
14 | ///
15 | /// Mathematically, `power` would return a complex number when base is negative and
16 | /// power is not an integral value. `power` can’t do that,
17 | /// so instead it signals domain error (returns `±NaN`).
18 | ///
19 | /// - Parameters
20 | /// - A: matrix
21 | /// - p: power to raise matrix to
22 | /// - Returns: elementwise matrix power of a raised to p
23 | public func power(_ A: Matrix, _ b: Double) -> Matrix {
24 | return matrixScalarOperation(power, A, b)
25 | }
26 |
27 | /// Exponentiation function, returning matrix raised to power.
28 | ///
29 | /// Alternatively, `A .^ p` can be executed with `power(A, p)`.
30 | ///
31 | /// Mathematically, `power` would return a complex number when base is negative and
32 | /// power is not an integral value. `power` can’t do that,
33 | /// so instead it signals domain error (returns `±NaN`).
34 | ///
35 | /// - Parameters
36 | /// - A: matrix
37 | /// - p: power to raise matrix to
38 | /// - Returns: elementwise matrix power of a raised to p
39 | public func .^ (_ A: Matrix, _ p: Double) -> Matrix {
40 | return power(A, p)
41 | }
42 |
43 | /// Exponentiation function, returning matrix raised to power of 2.
44 | ///
45 | /// - Parameters
46 | /// - A: matrix
47 | /// - Returns: elementwise vector power of a matrix to power of 2
48 | public func square(_ A: Matrix) -> Matrix {
49 | return matrixFunction(square, A)
50 | }
51 |
52 | /// Exponentiation function, returning square root of matrix.
53 | ///
54 | /// Mathematically, `sqrt` would return a complex number when base is negative.
55 | /// `sqrt` can’t do that, so instead it signals domain error (returns `±NaN`).
56 | ///
57 | /// - Parameters
58 | /// - A: matrix
59 | /// - Returns: elementwise square root of matrix A
60 | public func sqrt(_ A: Matrix) -> Matrix {
61 | return matrixFunction(sqrt, A)
62 | }
63 |
64 | /// Compute `e` (the base of natural logarithms) raised to the power `A`.
65 | ///
66 | /// If the magnitude of the result is too large to be representable, exp
67 | /// signals overflow (returns `Inf`).
68 | ///
69 | /// - Parameters
70 | /// - A: matrix
71 | /// - Returns: elementwise `e` raised to the power of matrix A
72 | public func exp(_ A: Matrix) -> Matrix {
73 | return matrixFunction(exp, A)
74 | }
75 |
76 | /// Compute the natural logarithm of `A` where `exp(log(A))` equals `A`, exactly in
77 | /// mathematics and approximately in C.
78 | ///
79 | /// If x is negative, log signals a domain error (returns `NaN`). If x is zero, it returns
80 | /// negative infinity (`-Inf`); if x is too close to zero, it may signal overflow.
81 | ///
82 | /// - Parameters
83 | /// - A: matrix
84 | /// - Returns: elementwise natural logarithm of matrix A
85 | public func log(_ A: Matrix) -> Matrix {
86 | return matrixFunction(log, A)
87 | }
88 |
89 | /// Return the base-2 logarithm of `A`, where `log2(A) = log(A)/log(2)`.
90 | ///
91 | /// - Parameters
92 | /// - A: matrix
93 | /// - Returns: elementwise base-2 logarithm of matrix A
94 | public func log2(_ A: Matrix) -> Matrix {
95 | return matrixFunction(log2, A)
96 | }
97 |
98 | /// Return the base-10 logarithm of `A`, where `log10(A) = log(A)/log(10)`.
99 | ///
100 | /// - Parameters
101 | /// - A: matrix
102 | /// - Returns: elementwise base-10 logarithm of matrix A
103 | public func log10(_ A: Matrix) -> Matrix {
104 | return matrixFunction(log10, A)
105 | }
106 |
--------------------------------------------------------------------------------
/Sources/MatrixLeastSquare.swift:
--------------------------------------------------------------------------------
1 | // MatrixLeastSquare.swift
2 | //
3 | // Created by Brett Larson on 9/10/20.
4 | // Copyright © 2020 Brett Larson. All rights reserved.
5 | //
6 | // This software may be modified and distributed under the terms
7 | // of the BSD license. See the LICENSE file for details.
8 |
9 | import Accelerate
10 |
11 | /// Compute the least squares solution to the overdetermined linear
12 | /// system A*X = B with full rank matrix A.
13 | ///
14 | /// A precondition errors throw for mismatched matrix dimensions
15 | /// or if algorithm fails.
16 | ///
17 | /// Requires M (rows of A) >= N (cols of A).
18 | ///
19 | /// - Parameters:
20 | /// - A: MxN matrix
21 | /// - B: MxK matrix
22 | /// - Returns:
23 | /// - X: NxK solution matrix
24 | /// - R: 1xK residuals
25 | public func lstsqr(_ A: Matrix, _ B: Matrix) -> (X: Matrix, R: Matrix) {
26 | precondition(A.rows >= A.cols, "A Matrix needs rows >= col")
27 | precondition(A.rows == B.rows, "A and B Matrix rows must be equal")
28 |
29 | // Copies of input that can be modified.
30 | // In the Intel example of dgels() I noticed the flat matrix has elements by rows
31 | // and then columns thus the next transposes. I tried changing TRANS to 'T'
32 | // to eliminate the transpose but could not find the correct set of other changes
33 | // to produce the correct solution.
34 | let at = Matrix(A.T)
35 | let bt = Matrix(B.T)
36 |
37 | var TRANS: Int8 = Int8(Array("N".utf8).first!) // No transpose
38 | var M = __CLPK_integer(A.rows)
39 | var N = __CLPK_integer(A.cols)
40 | var NRHS = __CLPK_integer(B.cols)
41 | var LDA = M
42 | var LDB = M
43 |
44 | var wkOpt = __CLPK_doublereal(0.0)
45 | var lWork = __CLPK_integer(-1)
46 |
47 | var info: __CLPK_integer = 0
48 |
49 | /* Query and allocate the optimal workspace */
50 | dgels_(&TRANS, &M, &N, &NRHS, &(at.flat), &LDA, &(bt.flat), &LDB, &wkOpt, &lWork, &info);
51 |
52 | precondition(info == 0, "Error finding optimal lWork")
53 | lWork = __CLPK_integer(wkOpt)
54 | var work = Vector(repeating: 0.0, count: Int(lWork))
55 |
56 | /* Compute least square solution */
57 | dgels_(&TRANS, &M, &N, &NRHS, &(at.flat), &LDA, &(bt.flat), &LDB, &work, &lWork, &info);
58 |
59 | precondition(info == 0, "Error")
60 |
61 | let X = bt.T[0..
77 | int dgels_(char *__trans, __CLPK_integer *__m, __CLPK_integer *__n,
78 | __CLPK_integer *__nrhs, __CLPK_doublereal *__a, __CLPK_integer *__lda,
79 | __CLPK_doublereal *__b, __CLPK_integer *__ldb,
80 | __CLPK_doublereal *__work, __CLPK_integer *__lwork,
81 | __CLPK_integer *__info)
82 | */
83 |
84 | /*
85 | Is there a problem defining Vector = [Double] = Array and
86 | passing dereferenced address with & to LAPACK function? See the
87 | description for ContiguousArray at:
88 |
89 | What I do not know is if "Double" is a class or @objc protocol. Will
90 | [Double] have contiguous data that LAPACK requires.
91 | */
92 |
93 | /*
94 | Reference Intel example of dgels() at:
95 |
96 | This includes a test case with data.
97 | */
98 |
99 | /*
100 | Reference LAPACK documentation for dgels() at:
101 |
102 | */
103 |
--------------------------------------------------------------------------------
/Sources/MatrixStatistics.swift:
--------------------------------------------------------------------------------
1 | // MatrixStatistics.swift
2 | //
3 | // Copyright (c) 2017 Alexander Taraymovich
4 | // All rights reserved.
5 | //
6 | // This software may be modified and distributed under the terms
7 | // of the BSD license. See the LICENSE file for details.
8 |
9 | import Accelerate
10 |
11 | // MARK: - Statistic functions on matrix
12 |
13 | /// Return vector of largest elements of matrix in a specified dimension.
14 | ///
15 | /// - Parameters
16 | /// - A: matrix
17 | /// - d: dimension (.Column or .Row, defaults to .Row)
18 | public func max(_ A: Matrix, _ d: Dim = .Row) -> Vector {
19 | return aggMatrixFunction(vDSP_maxvD, A, d)
20 | }
21 |
22 | /// Return vector of indices of largest elements of matrix in a specified dimension.
23 | ///
24 | /// - Parameters
25 | /// - A: matrix
26 | /// - d: dimension (.Column or .Row, defaults to .Row)
27 | public func maxi(_ A: Matrix, _ d: Dim = .Row) -> [Int] {
28 | return aggMatrixIFunction(vDSP_maxviD, A, d)
29 | }
30 |
31 | /// Return vector of smallest elements of matrix in a specified dimension.
32 | ///
33 | /// - Parameters
34 | /// - A: matrix
35 | /// - d: dimension (.Column or .Row, defaults to .Row)
36 | public func min(_ A: Matrix, _ d: Dim = .Row) -> Vector {
37 | return aggMatrixFunction(vDSP_minvD, A, d)
38 | }
39 |
40 | /// Return vector of indices of smallest elements of matrix in a specified dimension.
41 | ///
42 | /// - Parameters
43 | /// - A: matrix
44 | /// - d: dimension (.Column or .Row, defaults to .Row)
45 | public func mini(_ A: Matrix, _ d: Dim = .Row) -> [Int] {
46 | return aggMatrixIFunction(vDSP_minviD, A, d)
47 | }
48 |
49 | /// Return vector of mean values of matrix in a specified dimension.
50 | ///
51 | /// - Parameters
52 | /// - A: matrix
53 | /// - d: dimension (.Column or .Row, defaults to .Row)
54 | public func mean(_ A: Matrix, _ d: Dim = .Row) -> Vector {
55 | return aggMatrixFunction(vDSP_meanvD, A, d)
56 | }
57 |
58 | /// Return vector of standard deviation values of matrix in a specified dimension.
59 | ///
60 | /// - Parameters
61 | /// - A: matrix
62 | /// - d: dimension (.Column or .Row, defaults to .Row)
63 | public func std(_ A: Matrix, _ d: Dim = .Row) -> Vector {
64 | return aggMatrixFunction(std, A, d)
65 | }
66 |
67 | /// Return normalized matrix (substract mean value and divide by standard deviation)
68 | /// in dpecified dimension.
69 | ///
70 | /// - Parameters
71 | /// - A: matrix
72 | /// - d: dimension (.Column or .Row, defaults to .Row)
73 | /// - Returns: normalized matrix A
74 | public func normalize(_ A: Matrix, _ d: Dim = .Row) -> Matrix {
75 | switch d {
76 | case .Row:
77 | return Matrix(A.map { normalize(Vector($0)) })
78 | case .Column:
79 | return Matrix(transpose(A).map { normalize(Vector($0)) })
80 | }
81 | }
82 |
83 | /// Return vector of sums of values of matrix in a specified dimension.
84 | ///
85 | /// - Parameters
86 | /// - A: matrix
87 | /// - d: dimension (.Column or .Row, defaults to .Row)
88 | public func sum(_ A: Matrix, _ d: Dim = .Row) -> Vector {
89 | return aggMatrixFunction(vDSP_sveD, A, d)
90 | }
91 |
92 | /// Return vector of sums of squared values of matrix in a specified dimension.
93 | ///
94 | /// - Parameters
95 | /// - A: matrix
96 | /// - d: dimension (.Column or .Row, defaults to .Row)
97 | public func sumsq(_ A: Matrix, _ d: Dim = .Row) -> Vector {
98 | return aggMatrixFunction(vDSP_svesqD, A, d)
99 | }
100 |
--------------------------------------------------------------------------------
/Sources/MatrixTrigonometry.swift:
--------------------------------------------------------------------------------
1 | // MatrixTrigonometry.swift
2 | //
3 | // Copyright (c) 2017 Alexander Taraymovich
4 | // All rights reserved.
5 | //
6 | // This software may be modified and distributed under the terms
7 | // of the BSD license. See the LICENSE file for details.
8 |
9 | // MARK: - Trigonometric functions on matrix
10 |
11 | /// Return the sine of `A`, where `A` is given in radians and the return value is
12 | /// in the range -1 to 1.
13 | ///
14 | /// - Parameters
15 | /// - A: matrix
16 | /// - Returns: sine of a matrix values
17 | public func sin(_ A: Matrix) -> Matrix {
18 | return matrixFunction(sin, A)
19 | }
20 |
21 | /// Return the cosine of `A`, where `A` is given in radians and the return value is
22 | /// in the range -1 to 1.
23 | ///
24 | /// - Parameters
25 | /// - A: matrix
26 | /// - Returns: cosine of a matrix values
27 | public func cos(_ A: Matrix) -> Matrix {
28 | return matrixFunction(cos, A)
29 | }
30 |
31 | /// Return the tangent of `A`, where `A` is given in radians.
32 | ///
33 | /// Mathematically, the tangent function has singularities at odd multiples of
34 | /// pi/2. If the argument x is too close to one of these singularities, tan
35 | /// will return extremely large value.
36 | ///
37 | /// - Parameters
38 | /// - A: matrix
39 | /// - Returns: tangent of a matrix values
40 | public func tan(_ A: Matrix) -> Matrix {
41 | return matrixFunction(tan, A)
42 | }
43 |
44 | /// Return the arcsine of `A`, where return value is
45 | /// in the range -pi/2 to pi/2.
46 | ///
47 | /// - Parameters
48 | /// - A: matrix
49 | /// - Returns: arcsine of a matrix values
50 | public func asin(_ A: Matrix) -> Matrix {
51 | return matrixFunction(asin, A)
52 | }
53 |
54 | /// Return the arccosine of `A`, where return value is
55 | /// in the range 0 to pi.
56 | ///
57 | /// - Parameters
58 | /// - A: matrix
59 | /// - Returns: arccosine of a matrix values
60 | public func acos(_ A: Matrix) -> Matrix {
61 | return matrixFunction(acos, A)
62 | }
63 |
64 | /// Return the arctangent of `a`.
65 | ///
66 | /// - Parameters
67 | /// - A: matrix
68 | /// - Returns: arctangent of a matrix values
69 | public func atan(_ A: Matrix) -> Matrix {
70 | return matrixFunction(atan, A)
71 | }
72 |
--------------------------------------------------------------------------------
/Sources/Numeric.swift:
--------------------------------------------------------------------------------
1 | // Numeric.swift
2 | //
3 | // Copyright (c) 2017 Alexander Taraymovich
4 | // All rights reserved.
5 | //
6 | // This software may be modified and distributed under the terms
7 | // of the BSD license. See the LICENSE file for details.
8 |
9 | import Darwin
10 |
11 | precedencegroup EquivalencePrecedence {
12 | higherThan: ComparisonPrecedence
13 | lowerThan: AdditionPrecedence
14 | }
15 |
16 | infix operator ==~ : EquivalencePrecedence
17 | infix operator !=~ : EquivalencePrecedence
18 | infix operator <=~ : ComparisonPrecedence
19 | infix operator >=~ : ComparisonPrecedence
20 | infix operator <~ : ComparisonPrecedence
21 | infix operator >~ : ComparisonPrecedence
22 |
23 | // MARK: - Double equality and comparison
24 |
25 | let deps: Double = 1e-14
26 |
27 | func ==~ (left: Double, right: Double) -> Bool
28 | {
29 | return fabs(left.distance(to: right)) <= deps
30 | }
31 |
32 | func !=~ (left: Double, right: Double) -> Bool
33 | {
34 | return !(left ==~ right)
35 | }
36 |
37 | func <=~ (left: Double, right: Double) -> Bool
38 | {
39 | return left ==~ right || left <~ right
40 | }
41 |
42 | func >=~ (left: Double, right: Double) -> Bool
43 | {
44 | return left ==~ right || left >~ right
45 | }
46 |
47 | func <~ (left: Double, right: Double) -> Bool
48 | {
49 | return left.distance(to: right) > deps
50 | }
51 |
52 | func >~ (left: Double, right: Double) -> Bool
53 | {
54 | return left.distance(to: right) < -deps
55 | }
56 |
57 | // MARK: Double array comparison
58 |
59 | func ==~ (left: [Double], right: [Double]) -> Bool
60 | {
61 | return left.count == right.count &&
62 | zip(left, right).filter { (l, r) in l !=~ r }.count == 0
63 | }
64 |
65 | func !=~ (left: [Double], right: [Double]) -> Bool
66 | {
67 | return left.count != right.count ||
68 | zip(left, right).filter { (l, r) in l !=~ r }.count != 0
69 | }
70 |
71 | func >~ (left: [Double], right: [Double]) -> Bool
72 | {
73 | return left.count != right.count ||
74 | zip(left, right).filter { (l, r) in l >~ r }.count != 0
75 | }
76 |
77 | func <~ (left: [Double], right: [Double]) -> Bool
78 | {
79 | return left.count != right.count ||
80 | zip(left, right).filter { (l, r) in l <~ r }.count != 0
81 | }
82 |
83 | func >=~ (left: [Double], right: [Double]) -> Bool
84 | {
85 | return left.count != right.count ||
86 | zip(left, right).filter { (l, r) in l >=~ r }.count != 0
87 | }
88 |
89 | func <=~ (left: [Double], right: [Double]) -> Bool
90 | {
91 | return left.count != right.count ||
92 | zip(left, right).filter { (l, r) in l <=~ r }.count != 0
93 | }
94 |
95 | // MARK: Modulo operation
96 |
97 | infix operator %% : MultiplicationPrecedence
98 |
99 | func mod(_ a: Int, _ n: Int) -> Int {
100 | let r = a % abs(n)
101 | return r >= 0 ? r : r + abs(n)
102 | }
103 |
104 | func %% (_ a: Int, _ n: Int) -> Int {
105 | return mod(a, n)
106 | }
107 |
--------------------------------------------------------------------------------
/Sources/Operators.swift:
--------------------------------------------------------------------------------
1 | // Operators.swift
2 | //
3 | // Copyright (c) 2017 Alexander Taraymovich
4 | // All rights reserved.
5 | //
6 | // This software may be modified and distributed under the terms
7 | // of the BSD license. See the LICENSE file for details.
8 |
9 | #if !compiler(>=5)
10 | precedencegroup ExponentiationPrecedence {
11 | associativity: right
12 | higherThan: MultiplicationPrecedence
13 | }
14 | infix operator .^ : ExponentiationPrecedence
15 | #endif
16 |
17 | infix operator .* : MultiplicationPrecedence
18 | infix operator ./ : MultiplicationPrecedence
19 | infix operator ./. : MultiplicationPrecedence
20 |
21 | postfix operator ′
22 |
23 | infix operator ||| : DefaultPrecedence
24 |
--------------------------------------------------------------------------------
/Sources/Random.swift:
--------------------------------------------------------------------------------
1 | // Random.swift
2 | //
3 | // Copyright (c) 2017 Alexander Taraymovich
4 | // All rights reserved.
5 | //
6 | // This software may be modified and distributed under the terms
7 | // of the BSD license. See the LICENSE file for details.
8 |
9 | import Darwin
10 |
11 | /// Random value generator helpers
12 | public struct Random {
13 | /// Return random value uniformly distributed on specified interval
14 | ///
15 | /// - Parameters
16 | /// - range: interval
17 | public static func within(_ range: ClosedRange) -> T
18 | where T: FloatingPoint, T: ExpressibleByFloatLiteral {
19 | return (range.upperBound - range.lowerBound) *
20 | (T(arc4random()) / T(UInt32.max)) + range.lowerBound
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Sources/Util.swift:
--------------------------------------------------------------------------------
1 | // Util.swift
2 | //
3 | // Copyright (c) 2017 Alexander Taraymovich
4 | // All rights reserved.
5 | //
6 | // This software may be modified and distributed under the terms
7 | // of the BSD license. See the LICENSE file for details.
8 |
9 | import Accelerate
10 |
11 | // MARK: - Vector operations
12 |
13 | typealias Scalar = Double
14 |
15 | typealias VectorVectorOperation = ((_: UnsafePointer, _: vDSP_Stride, _: UnsafePointer, _: vDSP_Stride, _: UnsafeMutablePointer, _: vDSP_Stride, _: vDSP_Length) -> ())
16 |
17 | func vectorVectorOperation(_ op: VectorVectorOperation, _ a: Vector, _ b: Vector) -> Vector {
18 | precondition(a.count == b.count, "Vectors must have equal lenghts")
19 | var c = Vector(repeating: 0.0, count: a.count)
20 | op(a, 1, b, 1, &c, 1, vDSP_Length(a.count))
21 | return c
22 | }
23 |
24 | typealias VectorScalarOperation = ((_: UnsafePointer, _: vDSP_Stride, _: UnsafePointer, _: UnsafeMutablePointer, _: vDSP_Stride, _: vDSP_Length) -> ())
25 |
26 | func vectorScalarOperation(_ op: VectorScalarOperation, _ a: Vector, _ b: Double) -> Vector {
27 | var c = Vector(repeating: 0.0, count: a.count)
28 | var _b = b
29 | op(a, 1, &_b, &c, 1, vDSP_Length(a.count))
30 | return c
31 | }
32 |
33 | typealias UnaryVectorOperation = ((_: UnsafePointer, _: vDSP_Stride, _: UnsafeMutablePointer, _: vDSP_Stride, _: vDSP_Length) -> ())
34 |
35 | func unaryVectorOperation(_ op: UnaryVectorOperation, _ a: Vector) -> Vector {
36 | var c = Vector(repeating: 0.0, count: a.count)
37 | op(a, 1, &c, 1, vDSP_Length(a.count))
38 | return c
39 | }
40 |
41 | typealias VectorFunction = ((_: UnsafeMutablePointer, _: UnsafePointer, _: UnsafePointer) -> ())
42 |
43 | func vectorFunction(_ op: VectorFunction, _ a: Vector) -> Vector {
44 | var c = Vector(repeating: 0.0, count: a.count)
45 | var l = Int32(a.count)
46 | op(&c, a, &l)
47 | return c
48 | }
49 |
50 | typealias AggVectorFunction = ((_: UnsafePointer, _: vDSP_Stride, _: UnsafeMutablePointer, _: vDSP_Length) -> ())
51 |
52 | func aggVectorFunction(_ op: AggVectorFunction, _ a: Vector) -> Double {
53 | return aggVectorFunction(op, a, a.count)
54 | }
55 |
56 | func aggVectorFunction(_ op: AggVectorFunction, _ a: UnsafePointer, _ count: Int) -> Double {
57 | var c = 0.0
58 | op(a, 1, &c, vDSP_Length(count))
59 | return c
60 | }
61 |
62 | typealias AggVectorIFunction = ((_: UnsafePointer, _: vDSP_Stride, _: UnsafeMutablePointer, _: UnsafeMutablePointer, _: vDSP_Length) -> ())
63 |
64 | func aggVectorIFunction(_ op: AggVectorIFunction, _ a: Vector) -> Int {
65 | return aggVectorIFunction(op, a, a.count)
66 | }
67 |
68 | func aggVectorIFunction(_ op: AggVectorIFunction, _ a: UnsafePointer, _ count: Int) -> Int {
69 | var c = 0.0
70 | var i: vDSP_Length = 0
71 | op(a, 1, &c, &i, vDSP_Length(count))
72 | return Int(i)
73 | }
74 |
75 | // MARK: - Matrix operations
76 |
77 | typealias MatrixMatrixOperation = ((_ A: Vector, _ B: Vector) -> Vector)
78 |
79 | func matrixMatrixOperation(_ op: MatrixMatrixOperation, _ A: Matrix, _ B: Matrix) -> Matrix {
80 | precondition(A.rows == B.rows && A.cols == B.cols, "Matrices must be of same dimensions")
81 | return Matrix(A.rows, A.cols, op(A.flat, B.flat))
82 | }
83 |
84 | typealias MatrixScalarOperation = ((_ A: Vector, _ b: Double) -> Vector)
85 |
86 | func matrixScalarOperation(_ op: MatrixScalarOperation, _ A: Matrix, _ b: Double) -> Matrix {
87 | return Matrix(A.rows, A.cols, op(A.flat, b))
88 | }
89 |
90 | typealias InvMatrixScalarOperation = ((_ a: Double, _ B: Vector) -> Vector)
91 |
92 | func invMatrixScalarOperation(_ op: InvMatrixScalarOperation, _ a: Double, _ B: Matrix) -> Matrix {
93 | return Matrix(B.rows, B.cols, op(a, B.flat))
94 | }
95 |
96 | func matrixVectorOperation(_ op: MatrixMatrixOperation, _ A: Matrix, _ b: Vector) -> Matrix {
97 | let B = Matrix((0.. [Double] in
98 | return b
99 | })
100 | return Matrix(A.rows, A.cols, op(A.flat, B.flat))
101 | }
102 |
103 | func invMatrixVectorOperation(_ op: MatrixMatrixOperation, _ a: Vector, _ B: Matrix) -> Matrix {
104 | let A = Matrix((0.. [Double] in
105 | return a
106 | })
107 | return Matrix(B.rows, B.cols, op(A.flat, B.flat))
108 | }
109 |
110 | typealias MatrixFunction = ((_ A: Vector) -> Vector)
111 |
112 | func matrixFunction(_ op: MatrixFunction, _ A: Matrix) -> Matrix {
113 | return Matrix(A.rows, A.cols, op(A.flat))
114 | }
115 |
116 | typealias AggMatrixFunction = ((_ A: Vector) -> Double)
117 |
118 | func aggMatrixFunction(_ op: AggMatrixFunction, _ A: Matrix, _ d: Dim) -> Vector {
119 | let _A = toRows(A, d)
120 | var res = zeros(_A.rows)
121 | for i in (0..<_A.rows) {
122 | res[i] = op(_A[row: i])
123 | }
124 | return res
125 | }
126 |
127 | func aggMatrixFunction(_ op: AggVectorFunction, _ A: Matrix, _ d: Dim) -> Vector {
128 | let _A = toRows(A, d)
129 | var res = zeros(_A.rows)
130 | for i in (0..<_A.rows) {
131 | _A.flat.withUnsafeBufferPointer { bufPtr in
132 | let p = bufPtr.baseAddress! + i * _A.cols
133 | res[i] = aggVectorFunction(op, p, _A.cols)
134 | }
135 | }
136 | return res
137 | }
138 |
139 | func aggMatrixIFunction(_ op: AggVectorIFunction, _ A: Matrix, _ d: Dim) -> [Int] {
140 | let _A = toRows(A, d)
141 | var res = [Int](repeating: 0, count: _A.rows)
142 | for i in (0..<_A.rows) {
143 | _A.flat.withUnsafeBufferPointer { bufPtr in
144 | let p = bufPtr.baseAddress! + i * _A.cols
145 | res[i] = aggVectorIFunction(op, p, _A.cols)
146 | }
147 | }
148 | return res
149 | }
150 |
--------------------------------------------------------------------------------
/Sources/Vector.swift:
--------------------------------------------------------------------------------
1 | // Vector.swift
2 | //
3 | // Copyright (c) 2017 Alexander Taraymovich
4 | // All rights reserved.
5 | //
6 | // This software may be modified and distributed under the terms
7 | // of the BSD license. See the LICENSE file for details.
8 |
9 | import Accelerate
10 |
11 | /// Typealiasing of array of Doubles to Vector
12 | /// to make functions more mathematical.
13 | public typealias Vector = [Double]
14 |
15 | // MARK: - One-line creators for vectors
16 |
17 | /// Create a vector of zeros.
18 | ///
19 | /// - Parameters:
20 | /// - count: number of elements
21 | /// - Returns: zeros vector of specified size
22 | public func zeros(_ count: Int) -> Vector {
23 | return Vector(repeating: 0.0, count: count)
24 | }
25 |
26 | /// Create a vector of ones.
27 | ///
28 | /// - Parameters:
29 | /// - count: number of elements
30 | /// - Returns: ones vector of specified size
31 | public func ones(_ count: Int) -> Vector {
32 | return Vector(repeating: 1.0, count: count)
33 | }
34 |
35 | /// Create a vector of uniformly distributed on [0, 1) interval random values.
36 | ///
37 | /// - Parameters:
38 | /// - count: number of elements
39 | /// - Returns: random values vector of specified size
40 | public func rand(_ count: Int) -> Vector {
41 | var iDist = __CLPK_integer(1)
42 | var iSeed = (0..<4).map { _ in __CLPK_integer(Random.within(0.0...4095.0)) }
43 | var n = __CLPK_integer(count)
44 | var x = Vector(repeating: 0.0, count: count)
45 | dlarnv_(&iDist, &iSeed, &n, &x)
46 | return x
47 | }
48 |
49 | /// Create a vector of normally distributed random values.
50 | ///
51 | /// - Parameters:
52 | /// - count: number of elements
53 | /// - Returns: random values vector of specified size
54 | public func randn(_ count: Int) -> Vector {
55 | var iDist = __CLPK_integer(3)
56 | var iSeed = (0..<4).map { _ in __CLPK_integer(Random.within(0.0...4095.0)) }
57 | var n = __CLPK_integer(count)
58 | var x = Vector(repeating: 0.0, count: count)
59 | dlarnv_(&iDist, &iSeed, &n, &x)
60 | return x
61 | }
62 |
63 | // MARK: - Vector comparison
64 |
65 | /// Check if two vectors are equal using Double value approximate comparison
66 | public func == (lhs: Vector, rhs: Vector) -> Bool {
67 | return lhs ==~ rhs
68 | }
69 |
70 | /// Check if two vectors are not equal using Double value approximate comparison
71 | public func != (lhs: Vector, rhs: Vector) -> Bool {
72 | return lhs !=~ rhs
73 | }
74 |
75 | /// Check if one vector is greater than another using Double value approximate comparison
76 | public func > (lhs: Vector, rhs: Vector) -> Bool {
77 | return lhs >~ rhs
78 | }
79 |
80 | /// Check if one vector is less than another using Double value approximate comparison
81 | public func < (lhs: Vector, rhs: Vector) -> Bool {
82 | return lhs <~ rhs
83 | }
84 |
85 | /// Check if one vector is greater than or equal to another using Double value approximate comparison
86 | public func >= (lhs: Vector, rhs: Vector) -> Bool {
87 | return lhs >=~ rhs
88 | }
89 |
90 | /// Check if one vector is less than or equal to another using Double value approximate comparison
91 | public func <= (lhs: Vector, rhs: Vector) -> Bool {
92 | return lhs <=~ rhs
93 | }
94 |
--------------------------------------------------------------------------------
/Sources/VectorArithmetic.swift:
--------------------------------------------------------------------------------
1 | // Vector.swift
2 | //
3 | // Copyright (c) 2017 Alexander Taraymovich
4 | // All rights reserved.
5 | //
6 | // This software may be modified and distributed under the terms
7 | // of the BSD license. See the LICENSE file for details.
8 |
9 | import Darwin
10 | import Accelerate
11 |
12 | // MARK: - Arithmetic operations on two vectors
13 |
14 | /// Perform vector addition.
15 | ///
16 | /// Alternatively, `plus(a, b)` can be executed with `a + b`.
17 | ///
18 | /// - Parameters
19 | /// - a: left vector
20 | /// - b: right vector
21 | /// - Returns: elementwise vector sum of a and b
22 | public func plus(_ a: Vector, _ b: Vector) -> Vector {
23 | return vectorVectorOperation(vDSP_vaddD, a, b)
24 | }
25 |
26 | /// Perform vector addition.
27 | ///
28 | /// Alternatively, `a + b` can be executed with `plus(a, b)`.
29 | ///
30 | /// - Parameters
31 | /// - a: left vector
32 | /// - b: right vector
33 | /// - Returns: elementwise vector sum of a and b
34 | public func + (_ a: Vector, _ b: Vector) -> Vector {
35 | return plus(a, b)
36 | }
37 |
38 | /// Perform vector substraction.
39 | ///
40 | /// Alternatively, `minus(a, b)` can be executed with `a - b`.
41 | ///
42 | /// - Parameters
43 | /// - a: left vector
44 | /// - b: right vector
45 | /// - Returns: elementwise vector difference of a and b
46 | public func minus(_ a: Vector, _ b: Vector) -> Vector {
47 | return vectorVectorOperation(vDSP_vsubD, b, a)
48 | }
49 |
50 | /// Perform vector substraction.
51 | ///
52 | /// Alternatively, `a - b` can be executed with `minus(a, b)`.
53 | ///
54 | /// - Parameters
55 | /// - a: left vector
56 | /// - b: right vector
57 | /// - Returns: elementwise vector difference of a and b
58 | public func - (_ a: Vector, _ b: Vector) -> Vector {
59 | return minus(a, b)
60 | }
61 |
62 | /// Perform vector multiplication.
63 | ///
64 | /// Alternatively, `times(a, b)` can be executed with `a .* b`.
65 | ///
66 | /// - Parameters
67 | /// - a: left vector
68 | /// - b: right vector
69 | /// - Returns: elementwise vector product of a and b
70 | public func times(_ a: Vector, _ b: Vector) -> Vector {
71 | return vectorVectorOperation(vDSP_vmulD, a, b)
72 | }
73 |
74 | /// Perform vector multiplication.
75 | ///
76 | /// Alternatively, `a .* b` can be executed with `times(a, b)`.
77 | ///
78 | /// - Parameters
79 | /// - a: left vector
80 | /// - b: right vector
81 | /// - Returns: elementwise vector product of a and b
82 | public func .* (_ a: Vector, _ b: Vector) -> Vector {
83 | return times(a, b)
84 | }
85 |
86 | /// Perform vector right division.
87 | ///
88 | /// Alternatively, `rdivide(a, b)` can be executed with `a ./ b`.
89 | ///
90 | /// - Parameters
91 | /// - a: left vector
92 | /// - b: right vector
93 | /// - Returns: result of elementwise division of a by b
94 | public func rdivide(_ a: Vector, _ b: Vector) -> Vector {
95 | return vectorVectorOperation(vDSP_vdivD, b, a)
96 | }
97 |
98 | /// Perform vector right division.
99 | ///
100 | /// Alternatively, `a ./ b` can be executed with `rdivide(a, b)`.
101 | ///
102 | /// - Parameters
103 | /// - a: left vector
104 | /// - b: right vector
105 | /// - Returns: result of elementwise division of a by b
106 | public func ./ (_ a: Vector, _ b: Vector) -> Vector {
107 | return rdivide(a, b)
108 | }
109 |
110 | /// Perform vector left division.
111 | ///
112 | /// Alternatively, `ldivide(a, b)` can be executed with `a ./. b`.
113 | ///
114 | /// - Parameters
115 | /// - a: left vector
116 | /// - b: right vector
117 | /// - Returns: result of elementwise division of b by a
118 | public func ldivide(_ a: Vector, _ b: Vector) -> Vector {
119 | return vectorVectorOperation(vDSP_vdivD, a, b)
120 | }
121 |
122 | /// Perform vector left division.
123 | ///
124 | /// Alternatively, `a ./. b` can be executed with `ldivide(a, b)`.
125 | ///
126 | /// - Parameters
127 | /// - a: left vector
128 | /// - b: right vector
129 | /// - Returns: result of elementwise division of b by a
130 | public func ./. (_ a: Vector, _ b: Vector) -> Vector {
131 | return ldivide(a, b)
132 | }
133 |
134 | // MARK: - Dot product operations on two vectors
135 |
136 | /// Perform vector dot product operation.
137 | ///
138 | /// Alternatively, `dot(a, b)` can be executed with `a * b`.
139 | ///
140 | /// - Parameters
141 | /// - a: left vector
142 | /// - b: right vector
143 | /// - Returns: dot product of a and b
144 | public func dot(_ a: Vector, _ b: Vector) -> Double {
145 | precondition(a.count == b.count, "Vectors must have equal lenghts")
146 | var c: Double = 0.0
147 | vDSP_dotprD(a, 1, b, 1, &c, vDSP_Length(a.count))
148 | return c
149 | }
150 |
151 | /// Perform vector dot product operation.
152 | ///
153 | /// Alternatively, `a * b` can be executed with `dot(a, b)`.
154 | ///
155 | /// - Parameters
156 | /// - a: left vector
157 | /// - b: right vector
158 | /// - Returns: dot product of a and b
159 | public func * (_ a: Vector, _ b: Vector) -> Double {
160 | return dot(a, b)
161 | }
162 |
163 | // MARK: - Arithmetic operations on vector and scalar
164 |
165 | /// Perform vector and scalar addition.
166 | ///
167 | /// Scalar value expands to vector dimension
168 | /// and elementwise vector addition is performed.
169 | ///
170 | /// Alternatively, `plus(a, b)` can be executed with `a + b`.
171 | ///
172 | /// - Parameters
173 | /// - a: vector
174 | /// - b: scalar
175 | /// - Returns: elementwise sum of vector a and scalar b
176 | public func plus(_ a: Vector, _ b: Double) -> Vector {
177 | return vectorScalarOperation(vDSP_vsaddD, a, b)
178 | }
179 |
180 | /// Perform vector and scalar addition.
181 | ///
182 | /// Scalar value expands to vector dimension
183 | /// and elementwise vector addition is performed.
184 | ///
185 | /// Alternatively, `a + b` can be executed with `plus(a, b)`.
186 | ///
187 | /// - Parameters
188 | /// - a: vector
189 | /// - b: scalar
190 | /// - Returns: elementwise sum of vector a and scalar b
191 | public func + (_ a: Vector, _ b: Double) -> Vector {
192 | return plus(a, b)
193 | }
194 |
195 | /// Perform scalar and vector addition.
196 | ///
197 | /// Scalar value expands to vector dimension
198 | /// and elementwise vector addition is performed.
199 | ///
200 | /// Alternatively, `plus(a, b)` can be executed with `a + b`.
201 | ///
202 | /// - Parameters
203 | /// - a: scalar
204 | /// - b: vector
205 | /// - Returns: elementwise sum of scalar a and vector b
206 | public func plus(_ a: Double, _ b: Vector) -> Vector {
207 | return plus(b, a)
208 | }
209 |
210 | /// Perform scalar and vector addition.
211 | ///
212 | /// Scalar value expands to vector dimension
213 | /// and elementwise vector addition is performed.
214 | ///
215 | /// Alternatively, `a + b` can be executed with `plus(a, b)`.
216 | ///
217 | /// - Parameters
218 | /// - a: scalar
219 | /// - b: vector
220 | /// - Returns: elementwise sum of scalar a and vector b
221 | public func + (_ a: Double, _ b: Vector) -> Vector {
222 | return plus(a, b)
223 | }
224 |
225 | /// Perform vector and scalar substraction.
226 | ///
227 | /// Scalar value expands to vector dimension
228 | /// and elementwise vector substraction is performed.
229 | ///
230 | /// Alternatively, `minus(a, b)` can be executed with `a - b`.
231 | ///
232 | /// - Parameters
233 | /// - a: vector
234 | /// - b: scalar
235 | /// - Returns: elementwise difference of vector a and scalar b
236 | public func minus(_ a: Vector, _ b: Double) -> Vector {
237 | return vectorScalarOperation(vDSP_vsaddD, a, -b)
238 | }
239 |
240 | /// Perform vector and scalar substraction.
241 | ///
242 | /// Scalar value expands to vector dimension
243 | /// and elementwise vector substraction is performed.
244 | ///
245 | /// Alternatively, `a - b` can be executed with `minus(a, b)`.
246 | ///
247 | /// - Parameters
248 | /// - a: vector
249 | /// - b: scalar
250 | /// - Returns: elementwise difference of vector a and scalar b
251 | public func - (_ a: Vector, _ b: Double) -> Vector {
252 | return minus(a, b)
253 | }
254 |
255 | /// Perform scalar and vector substraction.
256 | ///
257 | /// Scalar value expands to vector dimension
258 | /// and elementwise vector addition is performed.
259 | ///
260 | /// Alternatively, `minus(a, b)` can be executed with `a - b`.
261 | ///
262 | /// - Parameters
263 | /// - a: scalar
264 | /// - b: vector
265 | /// - Returns: elementwise difference of scalar a and vector b
266 | public func minus(_ a: Double, _ b: Vector) -> Vector {
267 | return uminus(minus(b, a))
268 | }
269 |
270 | /// Perform scalar and vector substraction.
271 | ///
272 | /// Scalar value expands to vector dimension
273 | /// and elementwise vector addition is performed.
274 | ///
275 | /// Alternatively, `a - b` can be executed with `minus(a, b)`.
276 | ///
277 | /// - Parameters
278 | /// - a: scalar
279 | /// - b: vector
280 | /// - Returns: elementwise difference of scalar a and vector b
281 | public func - (_ a: Double, _ b: Vector) -> Vector {
282 | return minus(a, b)
283 | }
284 |
285 | /// Perform vector and scalar multiplication.
286 | ///
287 | /// Scalar value expands to vector dimension
288 | /// and elementwise vector multiplication is performed.
289 | ///
290 | /// Alternatively, `times(a, b)` can be executed with `a .* b`.
291 | ///
292 | /// - Parameters
293 | /// - a: vector
294 | /// - b: scalar
295 | /// - Returns: elementwise product of vector a and scalar b
296 | public func times(_ a: Vector, _ b: Double) -> Vector {
297 | return vectorScalarOperation(vDSP_vsmulD, a, b)
298 | }
299 |
300 | /// Perform vector and scalar multiplication.
301 | ///
302 | /// Scalar value expands to vector dimension
303 | /// and elementwise vector multiplication is performed.
304 | ///
305 | /// Alternatively, `a .* b` can be executed with `times(a, b)`.
306 | ///
307 | /// - Parameters
308 | /// - a: vector
309 | /// - b: scalar
310 | /// - Returns: elementwise product of vector a and scalar b
311 | public func .* (_ a: Vector, _ b: Double) -> Vector {
312 | return times(a, b)
313 | }
314 |
315 | /// Perform scalar and vector multiplication.
316 | ///
317 | /// Scalar value expands to vector dimension
318 | /// and elementwise vector multiplication is performed.
319 | ///
320 | /// Alternatively, `times(a, b)` can be executed with `a .* b`.
321 | ///
322 | /// - Parameters
323 | /// - a: scalar
324 | /// - b: vector
325 | /// - Returns: elementwise product of scalar a and vector b
326 | public func times(_ a: Double, _ b: Vector) -> Vector {
327 | return times(b, a)
328 | }
329 |
330 | /// Perform scalar and vector multiplication.
331 | ///
332 | /// Scalar value expands to vector dimension
333 | /// and elementwise vector multiplication is performed.
334 | ///
335 | /// Alternatively, `a .* b` can be executed with `times(a, b)`.
336 | ///
337 | /// - Parameters
338 | /// - a: scalar
339 | /// - b: vector
340 | /// - Returns: elementwise product of scalar a and vector b
341 | public func .* (_ a: Double, _ b: Vector) -> Vector {
342 | return times(a, b)
343 | }
344 |
345 | /// Perform vector and scalar right division.
346 | ///
347 | /// Scalar value expands to vector dimension
348 | /// and elementwise vector right division is performed.
349 | ///
350 | /// Alternatively, `rdivide(a, b)` can be executed with `a ./ b`.
351 | ///
352 | /// - Parameters
353 | /// - a: vector
354 | /// - b: scalar
355 | /// - Returns: result of elementwise division of vector a by scalar b
356 | public func rdivide(_ a: Vector, _ b: Double) -> Vector {
357 | return vectorScalarOperation(vDSP_vsdivD, a, b)
358 | }
359 |
360 | /// Perform vector and scalar right division.
361 | ///
362 | /// Scalar value expands to vector dimension
363 | /// and elementwise vector right division is performed.
364 | ///
365 | /// Alternatively, `a ./ b` can be executed with `rdivide(a, b)`.
366 | ///
367 | /// - Parameters
368 | /// - a: vector
369 | /// - b: scalar
370 | /// - Returns: result of elementwise division of vector a by scalar b
371 | public func ./ (_ a: Vector, _ b: Double) -> Vector {
372 | return rdivide(a, b)
373 | }
374 |
375 | /// Perform scalar and vector right division.
376 | ///
377 | /// Scalar value expands to vector dimension
378 | /// and elementwise vector right division is performed.
379 | ///
380 | /// Alternatively, `rdivide(a, b)` can be executed with `a ./ b`.
381 | ///
382 | /// - Parameters
383 | /// - a: scalar
384 | /// - b: vector
385 | /// - Returns: result of elementwise division of scalar a by vector b
386 | public func rdivide(_ a: Double, _ b: Vector) -> Vector {
387 | let c = Vector(repeating: a, count: b.count)
388 | return rdivide(c, b)
389 | }
390 |
391 | /// Perform scalar and vector right division.
392 | ///
393 | /// Scalar value expands to vector dimension
394 | /// and elementwise vector right division is performed.
395 | ///
396 | /// Alternatively, `a ./ b` can be executed with `rdivide(a, b)`.
397 | ///
398 | /// - Parameters
399 | /// - a: scalar
400 | /// - b: vector
401 | /// - Returns: result of elementwise division of scalar a by vector b
402 | public func ./ (_ a: Double, _ b: Vector) -> Vector {
403 | return rdivide(a, b)
404 | }
405 |
406 | /// Perform vector and scalar left division.
407 | ///
408 | /// Scalar value expands to vector dimension
409 | /// and elementwise vector left division is performed.
410 | ///
411 | /// Alternatively, `ldivide(a, b)` can be executed with `a ./. b`.
412 | ///
413 | /// - Parameters
414 | /// - a: vector
415 | /// - b: scalar
416 | /// - Returns: result of elementwise division of scalar b by vector a
417 | public func ldivide(_ a: Vector, _ b: Double) -> Vector {
418 | return rdivide(b, a)
419 | }
420 |
421 | /// Perform vector and scalar left division.
422 | ///
423 | /// Scalar value expands to vector dimension
424 | /// and elementwise vector left division is performed.
425 | ///
426 | /// Alternatively, `a ./. b` can be executed with `ldivide(a, b)`.
427 | ///
428 | /// - Parameters
429 | /// - a: vector
430 | /// - b: scalar
431 | /// - Returns: result of elementwise division of scalar b by vector a
432 | public func ./. (_ a: Vector, _ b: Double) -> Vector {
433 | return ldivide(a, b)
434 | }
435 |
436 | /// Perform scalar and vector left division.
437 | ///
438 | /// Scalar value expands to vector dimension
439 | /// and elementwise vector left division is performed.
440 | ///
441 | /// Alternatively, `ldivide(a, b)` can be executed with `a ./. b`.
442 | ///
443 | /// - Parameters
444 | /// - a: scalar
445 | /// - b: vector
446 | /// - Returns: result of elementwise division of vector b by scalar a
447 | public func ldivide(_ a: Double, _ b: Vector) -> Vector {
448 | return rdivide(b, a)
449 | }
450 |
451 | /// Perform scalar and vector left division.
452 | ///
453 | /// Scalar value expands to vector dimension
454 | /// and elementwise vector left division is performed.
455 | ///
456 | /// Alternatively, `a ./. b` can be executed with `ldivide(a, b)`.
457 | ///
458 | /// - Parameters
459 | /// - a: scalar
460 | /// - b: vector
461 | /// - Returns: result of elementwise division of vector b by scalar a
462 | public func ./. (_ a: Double, _ b: Vector) -> Vector {
463 | return ldivide(a, b)
464 | }
465 |
466 | // MARK: - Sign operations on vector
467 |
468 | /// Absolute value of vector.
469 | ///
470 | /// - Parameters
471 | /// - a: vector
472 | /// - Returns: vector of absolute values of elements of vector a
473 | public func abs(_ a: Vector) -> Vector {
474 | return unaryVectorOperation(vDSP_vabsD, a)
475 | }
476 |
477 | /// Negation of vector.
478 | ///
479 | /// Alternatively, `uminus(a)` can be executed with `-a`.
480 | ///
481 | /// - Parameters
482 | /// - a: vector
483 | /// - Returns: vector of negated values of elements of vector a
484 | public func uminus(_ a: Vector) -> Vector {
485 | return unaryVectorOperation(vDSP_vnegD, a)
486 | }
487 |
488 | /// Negation of vector.
489 | ///
490 | /// Alternatively, `-a` can be executed with `uminus(a)`.
491 | ///
492 | /// - Parameters
493 | /// - a: vector
494 | /// - Returns: vector of negated values of elements of vector a
495 | public prefix func - (_ a: Vector) -> Vector {
496 | return uminus(a)
497 | }
498 |
499 | /// Threshold function on vector.
500 | ///
501 | /// - Parameters
502 | /// - a: vector
503 | /// - Returns: vector with values less than certain value set to 0
504 | /// and keeps the value otherwise
505 | public func thr(_ a: Vector, _ t: Double) -> Vector {
506 | var b = zeros(a.count)
507 | var t = t
508 | vDSP_vthrD(a, 1, &t, &b, 1, vDSP_Length(a.count))
509 | return b
510 | }
511 |
--------------------------------------------------------------------------------
/Sources/VectorExponent.swift:
--------------------------------------------------------------------------------
1 | // VectorExponent.swift
2 | //
3 | // Copyright (c) 2017 Alexander Taraymovich
4 | // All rights reserved.
5 | //
6 | // This software may be modified and distributed under the terms
7 | // of the BSD license. See the LICENSE file for details.
8 |
9 | import Accelerate
10 |
11 | // MARK: - Power and exponential operations on vector
12 |
13 | /// Exponentiation function, returning vector raised to power.
14 | ///
15 | /// Alternatively, `power(a, p)` can be executed with `a .^ p`.
16 | ///
17 | /// Mathematically, `power` would return a complex number when base is negative and
18 | /// power is not an integral value. `power` can’t do that,
19 | /// so instead it signals domain error (returns `±NaN`).
20 | ///
21 | /// - Parameters
22 | /// - a: vector
23 | /// - p: power to raise vector to
24 | /// - Returns: elementwise vector power of a raised to p
25 | public func power(_ a: Vector, _ p: Double) -> Vector {
26 | var c = Vector(repeating: 0.0, count: a.count)
27 | var l = Int32(a.count)
28 | var p = p
29 | vvpows(&c, &p, a, &l)
30 | return c
31 | }
32 |
33 | /// Exponentiation function, returning vector raised to power.
34 | ///
35 | /// Alternatively, `a .^ p` can be executed with `power(a, p)`.
36 | ///
37 | /// Mathematically, `power` would return a complex number when base is negative and
38 | /// power is not an integral value. `power` can’t do that,
39 | /// so instead it signals domain error (returns `±NaN`).
40 | ///
41 | /// - Parameters
42 | /// - a: vector
43 | /// - p: power to raise vector to
44 | /// - Returns: elementwise vector power of a raised to p
45 | public func .^ (_ a: Vector, _ p: Double) -> Vector {
46 | return power(a, p)
47 | }
48 |
49 | /// Exponentiation function, returning vector raised to power of 2.
50 | ///
51 | /// - Parameters
52 | /// - a: vector
53 | /// - Returns: elementwise vector power of a raised to power of 2
54 | public func square(_ a: Vector) -> Vector {
55 | return unaryVectorOperation(vDSP_vsqD, a)
56 | }
57 |
58 | /// Exponentiation function, returning square root of vector.
59 | ///
60 | /// Mathematically, `sqrt` would return a complex number when base is negative.
61 | /// `sqrt` can’t do that, so instead it signals domain error (returns `±NaN`).
62 | ///
63 | /// - Parameters
64 | /// - a: vector
65 | /// - Returns: elementwise square root of vector a
66 | public func sqrt(_ a: Vector) -> Vector {
67 | return vectorFunction(vvsqrt, a)
68 | }
69 |
70 | /// Compute `e` (the base of natural logarithms) raised to the power `a`.
71 | ///
72 | /// If the magnitude of the result is too large to be representable, exp
73 | /// signals overflow (returns `Inf`).
74 | ///
75 | /// - Parameters
76 | /// - a: vector
77 | /// - Returns: elementwise `e` raised to the power of vector a
78 | public func exp(_ a: Vector) -> Vector {
79 | return vectorFunction(vvexp, a)
80 | }
81 |
82 | /// Compute the natural logarithm of `a` where `exp(log(a))` equals `a`, exactly in
83 | /// mathematics and approximately in C.
84 | ///
85 | /// If x is negative, log signals a domain error (returns `NaN`). If x is zero, it returns
86 | /// negative infinity (`-Inf`); if x is too close to zero, it may signal overflow.
87 | ///
88 | /// - Parameters
89 | /// - a: vector
90 | /// - Returns: elementwise natural logarithm of vector a
91 | public func log(_ a: Vector) -> Vector {
92 | return vectorFunction(vvlog, a)
93 | }
94 |
95 | /// Return the base-2 logarithm of `a`, where `log2(a) = log(a)/log(2)`.
96 | ///
97 | /// - Parameters
98 | /// - a: vector
99 | /// - Returns: elementwise base-2 logarithm of vector a
100 | public func log2(_ a: Vector) -> Vector {
101 | return vectorFunction(vvlog2, a)
102 | }
103 |
104 | /// Return the base-10 logarithm of `a`, where `log10(a) = log(a)/log(10)`.
105 | ///
106 | /// - Parameters
107 | /// - a: vector
108 | /// - Returns: elementwise base-10 logarithm of vector a
109 | public func log10(_ a: Vector) -> Vector {
110 | return vectorFunction(vvlog10, a)
111 | }
112 |
--------------------------------------------------------------------------------
/Sources/VectorStatistics.swift:
--------------------------------------------------------------------------------
1 | // VectorStatistics.swift
2 | //
3 | // Copyright (c) 2017 Alexander Taraymovich
4 | // All rights reserved.
5 | //
6 | // This software may be modified and distributed under the terms
7 | // of the BSD license. See the LICENSE file for details.
8 |
9 | import Accelerate
10 |
11 | // MARK: - Statistical operations on vector
12 |
13 | /// Return the largest element of vector.
14 | ///
15 | /// - Parameters
16 | /// - a: vector
17 | /// - Returns: largest element of vector a
18 | public func max(_ a: Vector) -> Double {
19 | return aggVectorFunction(vDSP_maxvD, a)
20 | }
21 |
22 | /// Return the index of largest element of vector.
23 | ///
24 | /// - Parameters
25 | /// - a: vector
26 | /// - Returns: index of largest element of vector a
27 | public func maxi(_ a: Vector) -> Int {
28 | return aggVectorIFunction(vDSP_maxviD, a)
29 | }
30 |
31 | /// Return the smallest element of vector.
32 | ///
33 | /// - Parameters
34 | /// - a: vector
35 | /// - Returns: smallest element of vector a
36 | public func min(_ a: Vector) -> Double {
37 | return aggVectorFunction(vDSP_minvD, a)
38 | }
39 |
40 | /// Return the index of smallest element of vector.
41 | ///
42 | /// - Parameters
43 | /// - a: vector
44 | /// - Returns: index of smallest element of vector a
45 | public func mini(_ a: Vector) -> Int {
46 | return aggVectorIFunction(vDSP_minviD, a)
47 | }
48 |
49 | /// Return mean (statistically average) value of vector.
50 | ///
51 | /// - Parameters
52 | /// - a: vector
53 | /// - Returns: mean value of vector a
54 | public func mean(_ a: Vector) -> Double {
55 | return aggVectorFunction(vDSP_meanvD, a)
56 | }
57 |
58 | /// Return standard deviation value of vector.
59 | ///
60 | /// - Parameters
61 | /// - a: vector
62 | /// - Returns: standard deviation value of vector a
63 | public func std(_ a: Vector) -> Double {
64 | var m: Double = 0.0
65 | var s: Double = 0.0
66 | var c = Vector(repeating: 0.0, count: a.count)
67 | vDSP_normalizeD(a, 1, &c, 1, &m, &s, vDSP_Length(a.count))
68 | return s
69 | }
70 |
71 | /// Return normalized vector (substract mean value and divide by standard deviation).
72 | ///
73 | /// - Parameters
74 | /// - a: vector
75 | /// - Returns: normalized vector a
76 | public func normalize(_ a: Vector) -> Vector {
77 | var m: Double = 0.0
78 | var s: Double = 0.0
79 | var c = Vector(repeating: 0.0, count: a.count)
80 | vDSP_normalizeD(a, 1, &c, 1, &m, &s, vDSP_Length(a.count))
81 | return c
82 | }
83 |
84 | /// Return sum of vector's elements.
85 | ///
86 | /// - Parameters
87 | /// - a: vector
88 | /// - Returns: sum of elements of vector a
89 | public func sum(_ a: Vector) -> Double {
90 | return aggVectorFunction(vDSP_sveD, a)
91 | }
92 |
93 | /// Return sum of vector's squared elements.
94 | ///
95 | /// - Parameters
96 | /// - a: vector
97 | /// - Returns: sum of squared elements of vector a
98 | public func sumsq(_ a: Vector) -> Double {
99 | return aggVectorFunction(vDSP_svesqD, a)
100 | }
101 |
--------------------------------------------------------------------------------
/Sources/VectorTrigonometry.swift:
--------------------------------------------------------------------------------
1 | // VectorTrigonometry.swift
2 | //
3 | // Copyright (c) 2017 Alexander Taraymovich
4 | // All rights reserved.
5 | //
6 | // This software may be modified and distributed under the terms
7 | // of the BSD license. See the LICENSE file for details.
8 |
9 | import Accelerate
10 |
11 | // MARK: - Trigonometric operations on vector
12 |
13 | /// Return the sine of `a`, where `a` is given in radians and the return value is
14 | /// in the range -1 to 1.
15 | ///
16 | /// - Parameters
17 | /// - a: vector
18 | /// - Returns: sine of a vector values
19 | public func sin(_ a: Vector) -> Vector {
20 | return vectorFunction(vvsin, a)
21 | }
22 |
23 | /// Return the cosine of `a`, where `a` is given in radians and the return value is
24 | /// in the range -1 to 1.
25 | ///
26 | /// - Parameters
27 | /// - a: vector
28 | /// - Returns: cosine of a vector values
29 | public func cos(_ a: Vector) -> Vector {
30 | return vectorFunction(vvcos, a)
31 | }
32 |
33 | /// Return the tangent of `a`, where `a` is given in radians.
34 | ///
35 | /// Mathematically, the tangent function has singularities at odd multiples of
36 | /// pi/2. If the argument x is too close to one of these singularities, tan
37 | /// will return extremely large value.
38 | ///
39 | /// - Parameters
40 | /// - a: vector
41 | /// - Returns: tangent of a vector values
42 | public func tan(_ a: Vector) -> Vector {
43 | return vectorFunction(vvtan, a)
44 | }
45 |
46 | /// Return the arcsine of `a`, where return value is
47 | /// in the range -pi/2 to pi/2.
48 | ///
49 | /// - Parameters
50 | /// - a: vector
51 | /// - Returns: arcsine of a vector values
52 | public func asin(_ a: Vector) -> Vector {
53 | return vectorFunction(vvasin, a)
54 | }
55 |
56 | /// Return the arccosine of `a`, where return value is
57 | /// in the range 0 to pi.
58 | ///
59 | /// - Parameters
60 | /// - a: vector
61 | /// - Returns: arccosine of a vector values
62 | public func acos(_ a: Vector) -> Vector {
63 | return vectorFunction(vvacos, a)
64 | }
65 |
66 | /// Return the arctangent of `a`.
67 | ///
68 | /// - Parameters
69 | /// - a: vector
70 | /// - Returns: arctangent of a vector values
71 | public func atan(_ a: Vector) -> Vector {
72 | return vectorFunction(vvatan, a)
73 | }
74 |
--------------------------------------------------------------------------------
/Tests/MatrixTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MatrixTests.swift
3 | // LASwift
4 | //
5 | // Created by Alexander Taraymovich on 28/02/2017.
6 | // Copyright © 2017 CocoaPods. All rights reserved.
7 | //
8 |
9 | import Darwin
10 |
11 | import Quick
12 | import Nimble
13 | import LASwift
14 |
15 | class MatrixSpec: QuickSpec {
16 | override func spec() {
17 | describe("Matrix construction tests") {
18 | let count = 10
19 |
20 | let m1 = ones(count, count+1)
21 |
22 | it("ones matrix has correct dimensions") {
23 | expect(m1.rows) == count
24 | expect(m1.cols) == count+1
25 | }
26 |
27 | it("ones matrix all ones") {
28 | for i in 0.. m2
319 | expect(m2) < m1
320 | }
321 | it("greater/less than or equal") {
322 | let m1 = Matrix([[11.0, 12.0], [13.0, 14.0]])
323 | let m2 = Matrix([[1.0, 2.0], [3.0, 4.0]])
324 | let m3 = Matrix([[1.0, 2.0], [3.0, 4.0]])
325 | expect(m1) >= m2
326 | expect(m2) <= m1
327 | expect(m2) >= m3
328 | expect(m2) <= m3
329 | }
330 | }
331 |
332 | describe("Matrix subscript") {
333 | it("[i,j]") {
334 | let m1 = Matrix([[1.0, 2.0], [3.0, 4.0]])
335 | expect(m1[1, 1]) == 4.0
336 | m1[1, 0] = 10.0
337 | expect(m1[1, 0]) == 10.0
338 | }
339 | it("index") {
340 | let m1 = Matrix([[1.0, 2.0], [3.0, 4.0]])
341 | expect(m1[3]) == 4.0
342 | m1[2] = 10.0
343 | expect(m1[2]) == 10.0
344 | expect(m1[1, 0]) == 10.0
345 | }
346 | it("row") {
347 | let m1 = Matrix([[1.0, 2.0], [3.0, 4.0]])
348 | expect(m1[row: 1]) == [3.0, 4.0]
349 | m1[row: 0] = [10.0, 20.0]
350 | expect(m1[row: 0]) == [10.0, 20.0]
351 | expect(m1[0, 0]) == 10.0
352 | expect(m1[0, 1]) == 20.0
353 | }
354 | it("column") {
355 | let m1 = Matrix([[1.0, 2.0], [3.0, 4.0]])
356 | expect(m1[col: 1]) == [2.0, 4.0]
357 | m1[col: 0] = [10.0, 30.0]
358 | expect(m1[col: 0]) == [10.0, 30.0]
359 | expect(m1[0, 0]) == 10.0
360 | expect(m1[1, 0]) == 30.0
361 | }
362 | }
363 |
364 | describe("Matrix range-based subscript") {
365 | it("[i,j] -> Matrix") {
366 | let m1 = Matrix([[1.0, 2.0, 3.0],
367 | [4.0, 5.0, 6.0],
368 | [7.0, 8.0, 9.0]])
369 | let m2 = Matrix([[10.0, 11.0],
370 | [12.0, 13.0]])
371 | expect(m1[0, 1].flat) == [2.0, 3.0, 5.0, 6.0, 8.0, 9.0]
372 | m1[1, 0] = m2
373 | expect(m1[1..<3, 0...1].flat) == [10.0, 11.0, 12.0, 13.0]
374 | }
375 | it("closed") {
376 | let m1 = Matrix([[1.0, 2.0, 3.0],
377 | [4.0, 5.0, 6.0],
378 | [7.0, 8.0, 9.0]])
379 | let m2 = Matrix([[10.0, 11.0],
380 | [12.0, 13.0]])
381 | expect(m1[1...2, 0...1].flat) == [4.0, 5.0, 7.0, 8.0]
382 | m1[0...1, 1...2] = m2
383 | expect(m1.flat) == [1.0, 10.0, 11.0, 4.0, 12.0, 13.0, 7.0, 8.0, 9.0]
384 | }
385 | it("open") {
386 | let m1 = Matrix([[1.0, 2.0, 3.0],
387 | [4.0, 5.0, 6.0],
388 | [7.0, 8.0, 9.0]])
389 | let m2 = Matrix([[10.0, 11.0],
390 | [12.0, 13.0]])
391 | expect(m1[1..<3, 0..<2].flat) == [4.0, 5.0, 7.0, 8.0]
392 | m1[0..<2, 1..<3] = m2
393 | expect(m1.flat) == [1.0, 10.0, 11.0, 4.0, 12.0, 13.0, 7.0, 8.0, 9.0]
394 | }
395 | it("partial") {
396 | let m1 = Matrix([[1.0, 2.0, 3.0],
397 | [4.0, 5.0, 6.0],
398 | [7.0, 8.0, 9.0]])
399 | let m2 = Matrix([[10.0, 11.0],
400 | [12.0, 13.0]])
401 | expect(m1[1..., ..<2].flat) == [4.0, 5.0, 7.0, 8.0]
402 | m1[1..., 1...] = m2
403 | expect(m1.flat) == [1.0, 2.0, 3.0, 4.0, 10.0, 11.0, 7.0, 12.0, 13.0]
404 | }
405 | it("unbounded") {
406 | let m1 = Matrix([[1.0, 2.0, 3.0],
407 | [4.0, 5.0, 6.0],
408 | [7.0, 8.0, 9.0]])
409 | let m2 = Matrix([[10.0, 11.0, 12.0]])
410 | expect(m1[..., 2...2].flat) == [3.0, 6.0, 9.0]
411 | m1[1...1, ...] = m2
412 | expect(m1.flat) == [1.0, 2.0, 3.0, 10.0, 11.0, 12.0, 7.0, 8.0, 9.0]
413 | }
414 | }
415 |
416 | describe("Matrix map/reduce") {
417 | it("map") {
418 | let m1 = Matrix([[1.0, 2.0], [3.0, 4.0]])
419 | let res = Matrix([[1.0, 4.0], [9.0, 16.0]])
420 | expect(map(m1, { $0 * $0 })) == res
421 | }
422 | it("map vec") {
423 | let m1 = Matrix([[1.0, 2.0], [3.0, 4.0]])
424 | let res = Matrix([[1.0, 4.0], [9.0, 16.0]])
425 | expect(map(m1, square)) == res
426 | }
427 | it("reduce rows") {
428 | let m1 = Matrix([[1.0, 2.0], [3.0, 4.0]])
429 | let res = [3.0, 7.0]
430 | expect(reduce(m1, sum)) == res
431 | expect(reduce(m1, sum, .Row)) == res
432 | }
433 | it("reduce cols") {
434 | let m1 = Matrix([[1.0, 2.0], [3.0, 4.0]])
435 | let res = [4.0, 6.0]
436 | expect(reduce(m1, sum, .Column)) == res
437 | }
438 | }
439 |
440 | describe("Matrix power and exponential tests") {
441 | it("power") {
442 | let m1 = Matrix([[1.0, 2.0], [3.0, 4.0]])
443 | let p = 3.0
444 | let res = Matrix([[1.0, 8.0], [27.0, 64.0]])
445 | expect(m1 .^ p) == res
446 | }
447 | it("square") {
448 | let m1 = Matrix([[1.0, 2.0], [3.0, 4.0]])
449 | let res = Matrix([[1.0, 4.0], [9.0, 16.0]])
450 | expect(square(m1)) == res
451 | expect(m1 .^ 2.0) == res
452 | }
453 | it("sqrt") {
454 | let m1 = Matrix([[1.0, 2.0], [3.0, 4.0]])
455 | let res = Matrix([[sqrt(1.0), sqrt(2.0)], [sqrt(3.0), sqrt(4.0)]])
456 | expect(sqrt(m1)) == res
457 | expect(m1 .^ 0.5) == res
458 | }
459 | it("exp") {
460 | let m1 = Matrix([[1.0, 2.0], [3.0, 4.0]])
461 | let res = Matrix([[exp(1.0), exp(2.0)], [exp(3.0), exp(4.0)]])
462 | expect(exp(m1)) == res
463 | }
464 | it("log") {
465 | let m1 = Matrix([[1.0, 2.0], [3.0, 4.0]])
466 | let res = Matrix([[log(1.0), log(2.0)], [log(3.0), log(4.0)]])
467 | expect(log(m1)) == res
468 | }
469 | it("log10") {
470 | let m1 = Matrix([[1.0, 2.0], [3.0, 4.0]])
471 | let res = Matrix([[log10(1.0), log10(2.0)], [log10(3.0), log10(4.0)]])
472 | expect(log10(m1)) == res
473 | }
474 | it("log2") {
475 | let m1 = Matrix([[1.0, 2.0], [3.0, 4.0]])
476 | let res = Matrix([[log2(1.0), log2(2.0)], [log2(3.0), log2(4.0)]])
477 | expect(log2(m1)) == res
478 | }
479 | }
480 |
481 | describe("Matrix trigonometric tests") {
482 | it("sin") {
483 | let m1 = Matrix([[1.0, 2.0], [3.0, 4.0]])
484 | let res = Matrix([[sin(1.0), sin(2.0)], [sin(3.0), sin(4.0)]])
485 | expect(sin(m1)) == res
486 | }
487 | it("cos") {
488 | let m1 = Matrix([[1.0, 2.0], [3.0, 4.0]])
489 | let res = Matrix([[cos(1.0), cos(2.0)], [cos(3.0), cos(4.0)]])
490 | expect(cos(m1)) == res
491 | }
492 | it("tan") {
493 | let m1 = Matrix([[1.0, 2.0], [3.0, 4.0]])
494 | let res = Matrix([[tan(1.0), tan(2.0)], [tan(3.0), tan(4.0)]])
495 | expect(tan(m1)) == res
496 | }
497 | it("asin") {
498 | let m1 = Matrix([[0.5, -0.5], [1.0, -1.0]])
499 | let res = Matrix([[asin(0.5), asin(-0.5)], [asin(1.0), asin(-1.0)]])
500 | expect(asin(m1)) == res
501 | }
502 | it("acos") {
503 | let m1 = Matrix([[0.5, -0.5], [1.0, -1.0]])
504 | let res = Matrix([[acos(0.5), acos(-0.5)], [acos(1.0), acos(-1.0)]])
505 | expect(acos(m1)) == res
506 | }
507 | it("atan") {
508 | let m1 = Matrix([[1.0, 2.0], [3.0, 4.0]])
509 | let res = Matrix([[atan(1.0), atan(2.0)], [atan(3.0), atan(4.0)]])
510 | expect(atan(m1)) == res
511 | }
512 | }
513 |
514 | describe("Matrix statistics tests") {
515 | it("max") {
516 | let m1 = Matrix([[1.0, 4.0], [3.0, 2.0]])
517 | let res1 = [4.0, 3.0]
518 | let res2 = [3.0, 4.0]
519 | expect(max(m1)).to(beCloseTo(res1))
520 | expect(max(m1, .Row)).to(beCloseTo(res1))
521 | expect(max(m1, .Column)).to(beCloseTo(res2))
522 | }
523 | it("maxi") {
524 | let m1 = Matrix([[1.0, 4.0], [3.0, 2.0]])
525 | let res1 = [1, 0]
526 | let res2 = [1, 0]
527 | expect(maxi(m1)) == res1
528 | expect(maxi(m1, .Row)) == res1
529 | expect(maxi(m1, .Column)) == res2
530 | }
531 | it("min") {
532 | let m1 = Matrix([[1.0, 4.0], [3.0, 2.0]])
533 | let res1 = [1.0, 2.0]
534 | let res2 = [1.0, 2.0]
535 | expect(min(m1)).to(beCloseTo(res1))
536 | expect(min(m1, .Row)).to(beCloseTo(res1))
537 | expect(min(m1, .Column)).to(beCloseTo(res2))
538 | }
539 | it("mini") {
540 | let m1 = Matrix([[1.0, 4.0], [3.0, 2.0]])
541 | let res1 = [0, 1]
542 | let res2 = [0, 1]
543 | expect(mini(m1)) == res1
544 | expect(mini(m1, .Row)) == res1
545 | expect(mini(m1, .Column)) == res2
546 | }
547 | it("mean") {
548 | let m1 = Matrix([[1.0, 4.0], [3.0, 2.0]])
549 | let res1 = [2.5, 2.5]
550 | let res2 = [2.0, 3.0]
551 | expect(mean(m1)).to(beCloseTo(res1))
552 | expect(mean(m1, .Row)).to(beCloseTo(res1))
553 | expect(mean(m1, .Column)).to(beCloseTo(res2))
554 | }
555 | it("std") {
556 | let m1 = Matrix([[1.0, 4.0], [3.0, 2.0]])
557 | let res1 = [sqrt(4.5 / 2.0), sqrt(0.5 / 2.0)]
558 | let res2 = [sqrt(2.0 / 2.0), sqrt(2.0 / 2.0)]
559 | expect(std(m1)).to(beCloseTo(res1))
560 | expect(std(m1, .Row)).to(beCloseTo(res1))
561 | expect(std(m1, .Column)).to(beCloseTo(res2))
562 | }
563 | it("normalize") {
564 | let m1 = Matrix([[1.0, 4.0], [3.0, 2.0]])
565 | let mr = mean(m1)
566 | let sr = std(m1)
567 | let mc = mean(m1, .Column)
568 | let sc = std(m1, .Column)
569 | let res1 = transpose((transpose(m1) - mr) ./ sr)
570 | let res2 = (m1 - mc) ./ sc
571 | expect(normalize(m1)) == res1
572 | expect(normalize(m1, .Row)) == res1
573 | expect(normalize(m1, .Column)) == res2
574 | }
575 | it("sum") {
576 | let m1 = Matrix([[1.0, 4.0], [3.0, 2.0]])
577 | let res1 = [5.0, 5.0]
578 | let res2 = [4.0, 6.0]
579 | expect(sum(m1)).to(beCloseTo(res1))
580 | expect(sum(m1, .Row)).to(beCloseTo(res1))
581 | expect(sum(m1, .Column)).to(beCloseTo(res2))
582 | }
583 | it("sumsq") {
584 | let m1 = Matrix([[1.0, 4.0], [3.0, 2.0]])
585 | let res1 = [17.0, 13.0]
586 | let res2 = [10.0, 20.0]
587 | expect(sumsq(m1)).to(beCloseTo(res1))
588 | expect(sumsq(m1, .Row)).to(beCloseTo(res1))
589 | expect(sumsq(m1, .Column)).to(beCloseTo(res2))
590 | }
591 | }
592 |
593 | describe("Matrix linear algebra tests") {
594 | it("trace") {
595 | let m1 = Matrix([[1.0, 0.0, 2.0],
596 | [-1.0, 5.0, 0.0],
597 | [0.0, 3.0, -9.0]])
598 | let res = -3.0
599 | expect(trace(m1)) == res
600 | }
601 | it("transpose") {
602 | let m1 = Matrix([[1.0, 4.0],
603 | [3.0, 2.0]])
604 | let res = Matrix([[1.0, 3.0],
605 | [4.0, 2.0]])
606 | expect(transpose(m1)) == res
607 | expect(m1′) == res
608 | expect(m1.T) == res
609 | }
610 | it("mtimes") {
611 | let m1 = Matrix([[1.0, 3.0, 5.0],
612 | [2.0, 4.0, 7.0]])
613 | let m2 = Matrix([[-5.0, 8.0, 11.0],
614 | [3.0, 9.0, 21.0],
615 | [4.0, 0.0, 8.0]])
616 | let res = Matrix([[24.0, 35.0, 114.0],
617 | [30.0, 52.0, 162.0]])
618 | expect(m1 * m2) == res
619 | expect(mtimes(m1, m2)) == res
620 | }
621 | it("mpower") {
622 | let m1 = Matrix([[1.0, 2.0],
623 | [3.0, 4.0]])
624 | let res1 = Matrix([[7.0, 10.0],
625 | [15.0, 22.0]])
626 | let res2 = inv(m1 * m1)
627 | let eye = Matrix([[1.0, 0.0],
628 | [0.0, 1.0]])
629 | expect(m1 ^ 1) == m1
630 | expect(m1 ^ 2) == res1
631 | expect(m1 ^ -2) == res2
632 | expect(m1 ^ 0) == eye
633 | }
634 | it("inverse") {
635 | let m1 = Matrix([[1.0, 0.0, 2.0],
636 | [-1.0, 5.0, 0.0],
637 | [0.0, 3.0, -9.0]])
638 | let res = Matrix([[0.88235294117647067, -0.11764705882352944, 0.19607843137254904],
639 | [0.17647058823529416, 0.17647058823529413, 0.03921568627450981],
640 | [0.058823529411764663, 0.058823529411764719, -0.098039215686274522]])
641 | expect(inv(m1)) == res
642 | expect(mpower(m1, -1)) == res
643 | expect(m1 ^ -1) == res
644 | let m2 = Matrix([[1.0, 0.0, 2.0], [-1.0, 5.0, 0.0]])
645 |
646 | #if !SWIFT_PACKAGE
647 | expect { () -> Void in _ = inv(m2) }.to(throwAssertion())
648 | expect { () -> Void in _ = inv(ones(3, 3)) }.to(throwAssertion())
649 | #endif
650 |
651 | expect(inv(m1) * m1) == eye(3, 3)
652 | }
653 | it("eigen") {
654 | let m1 = Matrix([[1.0000, 0.5000, 0.3333, 0.2500],
655 | [0.5000, 1.0000, 0.6667, 0.5000],
656 | [0.3333, 0.6667, 1.0000, 0.7500],
657 | [0.2500, 0.5000, 0.7500, 1.0000]])
658 | let e1 = eig(m1)
659 | expect(m1 * e1.V) == e1.V * e1.D
660 | let m2 = Matrix([[1.0, 0.0, 2.0],
661 | [-1.0, 5.0, 0.0]])
662 |
663 | #if !SWIFT_PACKAGE
664 | expect { () -> Void in _ = eig(m2) }.to(throwAssertion())
665 | #endif
666 | let m3 = Matrix([[0, 1],
667 | [-2, -3]])
668 | let e2 = eig(m3)
669 | expect(m3 * e2.V) == e2.V * e2.D
670 | let v3 = Matrix([[-1.0, 0.0],
671 | [0.0, -2.0]])
672 | expect(e2.D) == v3
673 |
674 | }
675 | it("svd") {
676 | let m1 = Matrix([[1.0, 2.0],
677 | [3.0, 4.0],
678 | [5.0, 6.0],
679 | [7.0, 8.0]])
680 | let usv = svd(m1)
681 | expect(usv.U * usv.S * usv.V′) == m1
682 | }
683 | it("gsvd") {
684 | let m1 = Matrix([[1.0, 6.0, 11.0],
685 | [2.0, 7.0, 12.0],
686 | [3.0, 8.0, 13.0],
687 | [4.0, 9.0, 14.0],
688 | [5.0, 10.0, 15.0]])
689 | let m2 = Matrix([[8.0, 1.0, 6.0],
690 | [3.0, 5.0, 7.0],
691 | [4.0, 9.0, 2.0]])
692 | let m3 = Matrix([[0.5700, -0.6457, -0.4279],
693 | [-0.7455, -0.3296, -0.4375],
694 | [-0.1702, -0.0135, -0.4470],
695 | [0.2966, 0.3026, -0.4566],
696 | [0.0490, 0.6187, -0.4661]])
697 | let (U, _, _, _, _, _) = gsvd(m1, m2)
698 | expect(U == m3)
699 |
700 | }
701 | it("chol") {
702 | let m1 = Matrix([[1, 1, 1, 1, 1],
703 | [1, 2, 3, 4, 5],
704 | [1, 3, 6, 10, 15],
705 | [1, 4, 10, 20, 35],
706 | [1, 5, 15, 35, 70]])
707 | let u = chol(m1)
708 | expect(u′ * u) == m1
709 | let l = chol(m1, .Lower)
710 | expect(l * l′) == m1
711 | }
712 | it("det") {
713 | let m = Matrix([[1.44, -7.84, -4.39, 4.53],
714 | [-9.96, -0.28, -3.24, 3.83],
715 | [-7.55, 3.24, 6.27, -6.64],
716 | [8.34, 8.09, 5.28, 2.06]])
717 | let d = det(m)
718 |
719 | expect(d).to(beCloseTo(-4044.7754))
720 | }
721 | it("lstsq") {
722 | // Setup
723 | let a1 = Matrix([[1.44, -7.84, -4.39, 4.53],
724 | [-9.96, -0.28, -3.24, 3.83],
725 | [-7.55, 3.24, 6.27, -6.64],
726 | [8.34, 8.09, 5.28, 2.06],
727 | [7.08, 2.52, 0.74, -2.47],
728 | [-5.45, -5.70, -1.19, 4.70]])
729 | let b1 = Matrix([[8.58, 9.35],
730 | [8.26, -4.43],
731 | [8.48, -0.70],
732 | [-5.28, -0.26],
733 | [5.72, -7.36],
734 | [8.93, -2.52]])
735 | let c2 = Matrix([[-0.4506, 0.2497],
736 | [-0.8491, -0.9020],
737 | [0.7066, 0.6323],
738 | [0.1288, 0.1351]])
739 | let d2 = Matrix([[195.3616, 107.05746]])
740 |
741 | // Run function
742 | let (c1, d1) = lstsqr(a1, b1)
743 |
744 | // Check solution matrix
745 | expect(c1.rows) == c2.rows
746 | expect(c1.cols) == c2.cols
747 | for i in 0.. Void in _ = m1 ?? (.Range(4, -2, 0), .All) }.to(throwAssertion())
1002 | expect { () -> Void in _ = m1 ?? (.Range(3, -2, -1), .All) }.to(throwAssertion())
1003 | expect { () -> Void in _ = m1 ?? (.All, .Range(5, -2, 0)) }.to(throwAssertion())
1004 | expect { () -> Void in _ = m1 ?? (.All, .Range(3, -2, -1)) }.to(throwAssertion())
1005 | expect { () -> Void in _ = m1 ?? (.Range(0, -2, 4), .All) }.to(throwAssertion())
1006 | expect { () -> Void in _ = m1 ?? (.Range(-1, -2, 3), .All) }.to(throwAssertion())
1007 | expect { () -> Void in _ = m1 ?? (.All, .Range(0, -2, 5)) }.to(throwAssertion())
1008 | expect { () -> Void in _ = m1 ?? (.All, .Range(-1, -2, 3)) }.to(throwAssertion())
1009 | expect { () -> Void in _ = m1 ?? (.Take(5), .All) }.to(throwAssertion())
1010 | expect { () -> Void in _ = m1 ?? (.Take(-1), .All) }.to(throwAssertion())
1011 | expect { () -> Void in _ = m1 ?? (.All, .Take(6)) }.to(throwAssertion())
1012 | expect { () -> Void in _ = m1 ?? (.All, .Take(-1)) }.to(throwAssertion())
1013 | expect { () -> Void in _ = m1 ?? (.Drop(5), .All) }.to(throwAssertion())
1014 | expect { () -> Void in _ = m1 ?? (.Drop(-1), .All) }.to(throwAssertion())
1015 | expect { () -> Void in _ = m1 ?? (.All, .Drop(6)) }.to(throwAssertion())
1016 | expect { () -> Void in _ = m1 ?? (.All, .Drop(-1)) }.to(throwAssertion())
1017 | #endif
1018 | }
1019 | }
1020 | }
1021 | }
1022 |
--------------------------------------------------------------------------------
/Tests/PerformanceTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PerformanceTests.swift
3 | // LASwift
4 | //
5 | // Created by Alexander Taraymovich on 15/03/2017.
6 | // Copyright © 2017 CocoaPods. All rights reserved.
7 | //
8 |
9 | import LASwift
10 | import XCTest
11 |
12 | class PerformanceTests: XCTestCase {
13 | let a = rand(1000, 1000)
14 | let b = rand(1000, 1000)
15 | let x = rand(1000000)
16 | let y = rand(1000000)
17 |
18 | func testRandomMatrix() {
19 | measure {
20 | _ = rand(1000, 1000)
21 | }
22 | }
23 |
24 | func testInvert() {
25 | measure {
26 | _ = inv(self.a)
27 | }
28 | }
29 |
30 | func testCholesky() {
31 | let aTa = transpose(a) * a
32 | measure {
33 | _ = chol(aTa)
34 | }
35 | }
36 |
37 | func testDot() {
38 | measure {
39 | _ = self.x * self.y
40 | }
41 | }
42 |
43 | func testTranspose() {
44 | measure {
45 | _ = transpose(self.a)
46 | }
47 | }
48 |
49 | func testMultiply() {
50 | measure {
51 | _ = self.a * self.b
52 | }
53 | }
54 |
55 | func testSigmoid() {
56 | measure {
57 | _ = 1 ./ (1 + exp(-self.a))
58 | }
59 | }
60 |
61 | func testReLU() {
62 | measure {
63 | _ = thr(self.a, 0)
64 | }
65 | }
66 |
67 | func testSumByRows() {
68 | measure {
69 | _ = sum(self.a, .Row)
70 | }
71 | }
72 |
73 | func testSumByColumns() {
74 | measure {
75 | _ = sum(self.a, .Column)
76 | }
77 | }
78 |
79 | func testMaxIndicesByRows() {
80 | measure {
81 | _ = maxi(self.a, .Row)
82 | }
83 | }
84 |
85 | func testMaxIndicesByColumns() {
86 | measure {
87 | _ = maxi(self.a, .Column)
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/Tests/VectorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // VectorTests.swift
3 | // LASwift
4 | //
5 | // Created by Alexander Taraymovich on 22/02/2017.
6 | // Copyright © 2017 CocoaPods. All rights reserved.
7 | //
8 |
9 | import Darwin
10 | import Quick
11 | import Nimble
12 | import LASwift
13 |
14 | class VectorSpec: QuickSpec {
15 | override func spec() {
16 | describe("Vector construction tests") {
17 |
18 | let vec1 = ones(10)
19 |
20 | it("ones vector has correct size") {
21 | expect(vec1.count) == 10
22 | }
23 |
24 | it("ones vector all ones") {
25 | for elem in vec1 {
26 | expect(elem) == 1.0
27 | }
28 | }
29 |
30 | let vec2 = zeros(10)
31 |
32 | it("zeros vector has correct size") {
33 | expect(vec2.count) == 10
34 | }
35 |
36 | it("zeros vector all zeros") {
37 | for elem in vec2 {
38 | expect(elem) == 0.0
39 | }
40 | }
41 |
42 | let vec3 = zeros(10)
43 |
44 | it("zeros vectors are equal") {
45 | expect(vec3) == vec2
46 | }
47 |
48 | it("zeros and ones vectors are not equal") {
49 | expect(vec2) != vec1
50 | }
51 |
52 | let vec4 = [Double](repeating: 1.0, count: 10)
53 |
54 | it("differently constructed ones vectors are equal") {
55 | expect(vec1) == vec4
56 | }
57 | }
58 |
59 | describe("Vector comparison") {
60 | it("equal") {
61 | let v1 = [1.0, 2.0]
62 | let v2 = [1.0, 2.0]
63 | expect(v1 == v2) == true
64 | }
65 | it("not equal") {
66 | let v1 = [1.0, 2.0]
67 | let v2 = [1.0, 4.0]
68 | expect(v1 != v2) == true
69 | }
70 | it("greater/less than") {
71 | let v1 = [11.0, 12.0]
72 | let v2 = [1.0, 2.0]
73 | expect(v1 > v2) == true
74 | expect(v2 < v1) == true
75 | }
76 | it("greater/less than or equal") {
77 | let v1 = [11.0, 12.0]
78 | let v2 = [1.0, 2.0]
79 | let v3 = [1.0, 2.0]
80 | expect(v1 >= v2) == true
81 | expect(v2 <= v1) == true
82 | expect(v2 >= v3) == true
83 | expect(v2 <= v3) == true
84 | }
85 | }
86 | describe("Vector arithmetic tests") {
87 | it("addition") {
88 | let vec1 = [1.0, 2.0, 3.0]
89 | let vec2 = [4.0, 5.0, 6.0]
90 | let res = [5.0, 7.0, 9.0]
91 | expect(vec1 + vec2).to(beCloseTo(res))
92 | }
93 |
94 | it("substraction") {
95 | let vec1 = [1.0, 2.0, 3.0]
96 | let vec2 = [4.0, 5.0, 6.0]
97 | let res = [-3.0, -3.0, -3.0]
98 | expect(vec1 - vec2).to(beCloseTo(res))
99 | }
100 |
101 | it("multiplication") {
102 | let vec1 = [1.0, 2.0, 3.0]
103 | let vec2 = [4.0, 5.0, 6.0]
104 | let res = [4.0, 10.0, 18.0]
105 | expect(vec1 .* vec2).to(beCloseTo(res))
106 | }
107 |
108 | it("right division") {
109 | let vec1 = [1.0, 2.0, 3.0]
110 | let vec2 = [4.0, 5.0, 6.0]
111 | let res = [1.0 / 4.0, 2.0 / 5.0, 3.0 / 6.0]
112 | expect(vec1 ./ vec2).to(beCloseTo(res))
113 | }
114 |
115 | it("left division") {
116 | let vec1 = [1.0, 2.0, 3.0]
117 | let vec2 = [4.0, 5.0, 6.0]
118 | let res = [4.0 / 1.0, 5.0 / 2.0, 6.0 / 3.0]
119 | expect(vec1 ./. vec2).to(beCloseTo(res))
120 | }
121 |
122 | it("scalar addition") {
123 | let vec = [1.0, 2.0, 3.0]
124 | let s = 7.0
125 | let res = [8.0, 9.0, 10.0]
126 | expect(vec + s).to(beCloseTo(res))
127 | expect(s + vec).to(beCloseTo(res))
128 | }
129 |
130 | it("scalar substraction") {
131 | let vec = [1.0, 2.0, 3.0]
132 | let s = 7.0
133 | let res1 = [-6.0, -5.0, -4.0]
134 | let res2 = [6.0, 5.0, 4.0]
135 | expect(vec - s).to(beCloseTo(res1))
136 | expect(s - vec).to(beCloseTo(res2))
137 | }
138 |
139 | it("scalar multiplication") {
140 | let vec = [1.0, 2.0, 3.0]
141 | let s = 7.0
142 | let res = [7.0, 14.0, 21.0]
143 | expect(vec .* s).to(beCloseTo(res))
144 | expect(s .* vec).to(beCloseTo(res))
145 | }
146 |
147 | it("scalar right division") {
148 | let vec = [1.0, 2.0, 3.0]
149 | let s = 7.0
150 | let res1 = [1.0 / 7.0, 2.0 / 7.0, 3.0 / 7.0]
151 | let res2 = [7.0 / 1.0, 7.0 / 2.0, 7.0 / 3.0]
152 | expect(vec ./ s).to(beCloseTo(res1))
153 | expect(s ./ vec).to(beCloseTo(res2))
154 | }
155 |
156 | it("scalar left division") {
157 | let vec = [1.0, 2.0, 3.0]
158 | let s = 7.0
159 | let res1 = [7.0 / 1.0, 7.0 / 2.0, 7.0 / 3.0]
160 | let res2 = [1.0 / 7.0, 2.0 / 7.0, 3.0 / 7.0]
161 | expect(vec ./. s).to(beCloseTo(res1))
162 | expect(s ./. vec).to(beCloseTo(res2))
163 | }
164 |
165 | it("negation") {
166 | let vec = [1.0, -2.0, 3.0]
167 | let res = [-1.0, 2.0, -3.0]
168 | expect(-vec).to(beCloseTo(res))
169 | }
170 |
171 | it("absolute") {
172 | let vec = [1.0, -2.0, 3.0]
173 | let res = [1.0, 2.0, 3.0]
174 | expect(abs(vec)).to(beCloseTo(res))
175 | }
176 |
177 | it("threshold") {
178 | let vec = [1.0, -2.0, 3.0]
179 | let res = [1.0, 0.0, 3.0]
180 | expect(thr(vec, 0.0)).to(beCloseTo(res))
181 | }
182 |
183 | it("dot product") {
184 | let vec1 = [1.0, 2.0, 3.0]
185 | let vec2 = [4.0, 5.0, 6.0]
186 | let res = 32.0
187 | expect(vec1 * vec2).to(beCloseTo(res))
188 | }
189 | }
190 |
191 | describe("Vector power and exponential tests") {
192 | it("power") {
193 | let vec = [1.0, 2.0, 3.0]
194 | let p = 3.0
195 | let res = [1.0, 8.0, 27.0]
196 | expect(vec .^ p).to(beCloseTo(res))
197 | }
198 | it("square") {
199 | let vec = [1.0, 2.0, 3.0]
200 | let res = [1.0, 4.0, 9.0]
201 | expect(square(vec)).to(beCloseTo(res))
202 | expect(square(vec)).to(beCloseTo(vec .^ 2))
203 | }
204 | it("sqrt") {
205 | let vec = [1.0, 2.0, 3.0]
206 | let res = [sqrt(1.0), sqrt(2.0), sqrt(3.0)]
207 | expect(sqrt(vec)).to(beCloseTo(res))
208 | expect(sqrt(vec)).to(beCloseTo(vec .^ 0.5))
209 | }
210 | it("exp") {
211 | let vec = [1.0, 2.0, 3.0]
212 | let res = [exp(1.0), exp(2.0), exp(3.0)]
213 | expect(exp(vec)).to(beCloseTo(res))
214 | }
215 | it("log") {
216 | let vec = [1.0, 2.0, 3.0]
217 | let res = [log(1.0), log(2.0), log(3.0)]
218 | expect(log(vec)).to(beCloseTo(res))
219 | }
220 | it("log10") {
221 | let vec = [1.0, 2.0, 3.0]
222 | let res = [log10(1.0), log10(2.0), log10(3.0)]
223 | expect(log10(vec)).to(beCloseTo(res))
224 | }
225 | it("log2") {
226 | let vec = [1.0, 2.0, 3.0]
227 | let res = [log2(1.0), log2(2.0), log2(3.0)]
228 | expect(log2(vec)).to(beCloseTo(res))
229 | }
230 | }
231 |
232 | describe("Vector trigonometric tests") {
233 | it("sin") {
234 | let vec = [1.0, 2.0, 3.0]
235 | let res = [sin(1.0), sin(2.0), sin(3.0)]
236 | expect(sin(vec)).to(beCloseTo(res))
237 | }
238 | it("cos") {
239 | let vec = [1.0, 2.0, 3.0]
240 | let res = [cos(1.0), cos(2.0), cos(3.0)]
241 | expect(cos(vec)).to(beCloseTo(res))
242 | }
243 | it("tan") {
244 | let vec = [1.0, 2.0, 3.0]
245 | let res = [tan(1.0), tan(2.0), tan(3.0)]
246 | expect(tan(vec)).to(beCloseTo(res))
247 | }
248 | it("asin") {
249 | let vec = [1.0, 2.0, 3.0]
250 | let res = [asin(1.0), asin(2.0), asin(3.0)]
251 | expect(asin(vec)).to(beCloseTo(res))
252 | }
253 | it("acos") {
254 | let vec = [1.0, 2.0, 3.0]
255 | let res = [acos(1.0), acos(2.0), acos(3.0)]
256 | expect(acos(vec)).to(beCloseTo(res))
257 | }
258 | it("atan") {
259 | let vec = [1.0, 2.0, 3.0]
260 | let res = [atan(1.0), atan(2.0), atan(3.0)]
261 | expect(atan(vec)).to(beCloseTo(res))
262 | }
263 | }
264 |
265 | describe("Vector statistics tests") {
266 | it("max") {
267 | let vec = [1.0, 3.0, 2.0]
268 | let res = 3.0
269 | expect(max(vec)).to(beCloseTo(res))
270 | }
271 | it("maxi") {
272 | let vec = [1.0, 3.0, 2.0]
273 | let res = 1
274 | expect(maxi(vec)) == res
275 | }
276 | it("min") {
277 | let vec = [3.0, 1.0, 2.0]
278 | let res = 1.0
279 | expect(min(vec)).to(beCloseTo(res))
280 | }
281 | it("mini") {
282 | let vec = [3.0, 1.0, 2.0]
283 | let res = 1
284 | expect(mini(vec)) == res
285 | }
286 | it("mean") {
287 | let vec = [1.0, 2.0, 3.0]
288 | let res = 2.0
289 | expect(mean(vec)).to(beCloseTo(res))
290 | }
291 | it("std") {
292 | let vec = [1.0, 2.0, 3.0]
293 | let res = sqrt(2.0 / 3.0)
294 | expect(std(vec)).to(beCloseTo(res))
295 | }
296 | it("sum") {
297 | let vec = [1.0, 2.0, 3.0]
298 | let res = 6.0
299 | expect(sum(vec)).to(beCloseTo(res))
300 | }
301 | it("sumsq") {
302 | let vec = [1.0, 2.0, 3.0]
303 | let res = 14.0
304 | expect(sumsq(vec)).to(beCloseTo(res))
305 | }
306 | it("normalize") {
307 | let vec = [1.0, 2.0, 3.0]
308 | let m = mean(vec)
309 | let s = std(vec)
310 | let res = [(1.0 - m) / s, (2.0 - m) / s, (3.0 - m) / s]
311 | expect(normalize(vec)).to(beCloseTo(res))
312 | }
313 | }
314 | }
315 | }
316 |
--------------------------------------------------------------------------------