├── .github └── workflows │ └── macOS.yml ├── .gitignore ├── .swiftpm └── xcode │ └── package.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── LICENSE ├── Package.resolved ├── Package.swift ├── README.md ├── Sources └── LANumerics │ ├── AsPointer.swift │ ├── Functional.swift │ ├── LANumeric+Complex.swift │ ├── LANumeric+Double.swift │ ├── LANumeric+Float.swift │ ├── LANumeric.swift │ ├── Matrix.swift │ ├── SIMD.swift │ ├── Shape.swift │ └── ToStringWithPrecision.swift └── Tests └── LANumericsTests └── LANumericsTests.swift /.github/workflows/macOS.yml: -------------------------------------------------------------------------------- 1 | name: Build & Test 2 | 3 | on: push 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: macos-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: Build 13 | run: swift build -v 14 | - name: Run tests 15 | run: swift test -v 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | xcuserdata/ 6 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Steven Obua 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "swift-numerics", 6 | "repositoryURL": "https://github.com/apple/swift-numerics", 7 | "state": { 8 | "branch": null, 9 | "revision": "6583ac70c326c3ee080c1d42d9ca3361dca816cd", 10 | "version": "0.1.0" 11 | } 12 | } 13 | ] 14 | }, 15 | "version": 1 16 | } 17 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.1 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "LANumerics", 8 | products: [ 9 | // Products define the executables and libraries produced by a package, and make them visible to other packages. 10 | .library( 11 | name: "LANumerics", 12 | targets: ["LANumerics"]), 13 | ], 14 | dependencies: [ 15 | .package(url: "https://github.com/apple/swift-numerics", from: "0.1.0") 16 | // Dependencies declare other packages that this package depends on. 17 | // .package(url: /* package url */, from: "1.0.0"), 18 | ], 19 | targets: [ 20 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 21 | // Targets can depend on other targets in this package, and on products in packages which this package depends on. 22 | .target( 23 | name: "LANumerics", 24 | dependencies: [.product(name: "Numerics", package: "swift-numerics")]), 25 | .testTarget( 26 | name: "LANumericsTests", 27 | dependencies: ["LANumerics"]), 28 | ] 29 | ) 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LANumerics ![](https://github.com/phlegmaticprogrammer/LANumerics/workflows/Build%20%26%20Test/badge.svg) 2 | 3 | Copyright (c) 2020 Steven Obua 4 | 5 | License: MIT License 6 | 7 | *LANumerics* is a Swift package for doing *numerical linear algebra*. 8 | 9 | The package depends on [Swift Numerics](https://github.com/apple/swift-numerics), as it supports both **real** and **complex** numerics for both `Float` and `Double` precision in a uniform way. 10 | Under the hood it relies on the [`Accelerate`](https://developer.apple.com/documentation/accelerate) framework for most of its functionality, in particular `BLAS` and `LAPACK`, and also `vDSP`. 11 | 12 | Examining the [current tests](https://github.com/phlegmaticprogrammer/LANumerics/tree/master/Tests/LANumericsTests) provides a good starting point beyond this README. 13 | 14 | ## Table of Contents 15 | 16 | * [Usage](#usage) 17 | * [LANumeric](#lanumeric) 18 | * [Constructing Matrices](#constructing-matrices) 19 | * [SIMD Support](#simd-support) 20 | * [Matrix Arithmetic](#matrix-arithmetic) 21 | * [Solving Linear Equations](#solving-linear-equations) 22 | * [Linear Least Squares](#linear-least-squares) 23 | * [Matrix Decompositions](#matrix-decompositions) 24 | 25 | --- 26 | 27 | ## Usage 28 | 29 | *LANumerics* is a normal Swift package and can be added to your app [in the usual way](https://developer.apple.com/documentation/xcode/adding_package_dependencies_to_your_app). 30 | After adding it to your app, import `LANumerics` (and also `Numerics` if you use complex numbers). 31 | 32 | You can try out if everything works fine by running 33 | 34 | ```swift 35 | import LANumerics 36 | let A : Matrix = Matrix(columns: [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]) 37 | print("A: \(A)") 38 | ``` 39 | 40 | which should output something like 41 | 42 | ``` 43 | A: 4x3-matrix: 44 | ⎛1.0 5.0 9.0 ⎞ 45 | ⎜2.0 6.0 10.0⎟ 46 | ⎜3.0 7.0 11.0⎟ 47 | ⎝4.0 8.0 12.0⎠ 48 | ``` 49 | 50 | ## LANumeric 51 | 52 | The `LANumeric` protocol denotes the type of numbers on which *LANumerics* operates. It is implemented by the following types: 53 | 54 | * `Float` 55 | * `Double` 56 | * `Complex` 57 | * `Complex` 58 | 59 | Most functionality of *LANumerics* is generic in `LANumeric`, e.g. constructing matrices and computing with them, solving a system of linear equations, or computing the singular value decomposition of a matrix. 60 | 61 | ## Constructing Matrices 62 | 63 | The main work horse of *LANumerics* is the `Matrix` type. For convenience there is also a `Vector` type, but this is just a typealias for normal Swift arrays. 64 | 65 | The expression `Matrix([1,2,3])` constructs the matrix: 66 | ``` 67 | 3x1-matrix: 68 | ⎛1.0⎞ 69 | ⎜2.0⎟ 70 | ⎝3.0⎠ 71 | ``` 72 | The expression `Matrix(row: [1, 2, 3])` constructs the matrix: 73 | ``` 74 | 1x3-matrix: 75 | (1.0 2.0 3.0) 76 | ``` 77 | The expression `Matrix(rows: 2, columns: 3)` constructs a matrix consisting only of zeros: 78 | ``` 79 | 2x3-matrix: 80 | ⎛0.0 0.0 0.0⎞ 81 | ⎝0.0 0.0 0.0⎠ 82 | ``` 83 | The expression `Matrix(repeating: 1, rows: 2, columns: 3)` constructs a matrix consisting only of ones: 84 | ``` 85 | 2x3-matrix: 86 | ⎛1.0 1.0 1.0⎞ 87 | ⎝1.0 1.0 1.0⎠ 88 | ``` 89 | Given the two vectors `v1` and `v2` 90 | ```swift 91 | let v1 : Vector = [1, 2, 3] 92 | let v2 : Vector = [4, 5, 6] 93 | ``` 94 | we can create a matrix from columns `Matrix(columns: [v1, v2])`: 95 | ``` 96 | 3x2-matrix: 97 | ⎛1.0 4.0⎞ 98 | ⎜2.0 5.0⎟ 99 | ⎝3.0 6.0⎠ 100 | ``` 101 | or rows `Matrix(rows: [v1, v2])`: 102 | ``` 103 | 2x3-matrix: 104 | ⎛1.0 2.0 3.0⎞ 105 | ⎝4.0 5.0 6.0⎠ 106 | ``` 107 | It is also legal to create matrices with zero columns and/or rows, like `Matrix(rows: 2, columns: 0)` or `Matrix(rows: 0, columns: 0)`. 108 | 109 | ## SIMD Support 110 | 111 | Swift supports `simd` vector and matrix operations. *LANumerics* plays nice with `simd` by providing conversion functions to and from `simd` vectors and matrices. For example, starting from 112 | ```swift 113 | import simd 114 | import LANumerics 115 | 116 | let m = Matrix(rows: [[1, 2, 3], [4, 5, 6]]) 117 | print("m: \(m)") 118 | ``` 119 | with output 120 | ``` 121 | m: 2x3-matrix: 122 | ⎛1.0 2.0 3.0⎞ 123 | ⎝4.0 5.0 6.0⎠ 124 | ``` 125 | we can convert `m` into a `simd` matrix `s` via 126 | ```swift 127 | let s = m.simd3x2 128 | print(s) 129 | ``` 130 | resulting in the output 131 | ``` 132 | simd_double3x2(columns: (SIMD2(1.0, 4.0), SIMD2(2.0, 5.0), SIMD2(3.0, 6.0))) 133 | ``` 134 | Note that `simd` reverses the role of row and column indices compared to `LANumerics` (and usual mathematical convention). 135 | 136 | We can also convert `s` back: 137 | ```swift 138 | print(Matrix(s) == m) 139 | ``` 140 | will yield the output `true`. 141 | 142 | ## Accessing Matrix Elements and Submatrices 143 | 144 | Matrix elements and submatrices can be accessed using familiar notation. Given 145 | ```swift 146 | import simd 147 | import LANumerics 148 | 149 | var m = Matrix(rows: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]) 150 | print(m) 151 | ``` 152 | with output 153 | ``` 154 | 3x3-matrix: 155 | ⎛1.0 2.0 3.0⎞ 156 | ⎜4.0 5.0 6.0⎟ 157 | ⎝7.0 8.0 9.0⎠ 158 | ``` 159 | we can access the element at row 2 and column 1 via 160 | ``` 161 | m[2, 1] 162 | ``` 163 | which yields `8.0`. We can also set the element at row 2 and column 1 to some value: 164 | ``` 165 | m[2, 1] = 0 166 | print(m) 167 | ``` 168 | The output of running this is 169 | ``` 170 | 3x3-matrix: 171 | ⎛1.0 2.0 3.0⎞ 172 | ⎜4.0 5.0 6.0⎟ 173 | ⎝7.0 0.0 9.0⎠ 174 | ``` 175 | We can also access submatrices of `m`, for example its top-left and bottom-right 2x2 submatrices: 176 | ``` 177 | print(m[0 ... 1, 0 ... 1]) 178 | print(m[1 ... 2, 1 ... 2]) 179 | 180 | ``` 181 | This will print 182 | ``` 183 | 2x2-matrix: 184 | ⎛1.0 2.0⎞ 185 | ⎝4.0 5.0⎠ 186 | 2x2-matrix: 187 | ⎛5.0 6.0⎞ 188 | ⎝0.0 9.0⎠ 189 | ``` 190 | Finally, using the same notation, we can overwrite submatrices of `m`: 191 | ``` 192 | m[0 ... 1, 0 ... 1] = m[1 ... 2, 1 ... 2] 193 | print(m) 194 | ``` 195 | This overwrites the top-left 2x2 submatrix of `m` with its bottom-right 2x2 submatrix, yielding: 196 | ``` 197 | 3x3-matrix: 198 | ⎛5.0 6.0 3.0⎞ 199 | ⎜0.0 9.0 6.0⎟ 200 | ⎝7.0 0.0 9.0⎠ 201 | ``` 202 | 203 | ## Matrix Arithmetic 204 | 205 | *LANumerics* supports common operations on matrices and vectors, among them: 206 | 207 | * `transpose` and `adjoint` 208 | * matrix multiplication 209 | * vector products 210 | * element-wise operations 211 | * functional operations 212 | 213 | In the following, assume the context 214 | ```swift 215 | import Numerics 216 | import LANumerics 217 | let u = Matrix>(rows: [[1, 2 * .i], [3, 4 * .i + 1]]) 218 | let v = Matrix>(rows: [[.i, 0], [0, 1 + 1 * .i]]) 219 | print("u : \(u)\n") 220 | print("v : \(v)\n") 221 | ``` 222 | which has output 223 | ``` 224 | u : 2x2-matrix: 225 | ⎛1.0 2.0i ⎞ 226 | ⎝3.0 1.0 + 4.0i⎠ 227 | 228 | v : 2x2-matrix: 229 | ⎛1.0i 0.0 ⎞ 230 | ⎝0.0 1.0 + 1.0i⎠ 231 | ``` 232 | 233 | ### Transpose and Adjoint 234 | For **real** matrices, `transpose` and `adjoint` have the same meaning, but for **complex** matrices the `adjoint` is the element-wise conjugate of the `transpose`. Executing 235 | ```swift 236 | print("u.transpose : \(u.transpose)\n") 237 | print("u.adjoint : \(u.adjoint)\n") 238 | ``` 239 | thus yields 240 | ``` 241 | u.transpose : 2x2-matrix: 242 | ⎛1.0 3.0 ⎞ 243 | ⎝2.0i 1.0 + 4.0i⎠ 244 | 245 | u.adjoint : 2x2-matrix: 246 | ⎛1.0 3.0 ⎞ 247 | ⎝-2.0i 1.0 - 4.0i⎠ 248 | ``` 249 | The `adjoint` has the advantage over the `transpose` that many properties involving the adjoint generalize naturally from real matrices to complex matrices. Therefore there is the shortcut notation 250 | ```swift 251 | u′ 252 | ``` 253 | for `u.adjoint`. 254 | 255 | Note that `′` is the unicode character "Prime" `U+2032`. You can use for example [Ukelele](https://software.sil.org/ukelele/) to make the input of that character smooth. Other alternatives are configuring the touchbar of your macbook, or using a configurable keyboard like [Stream Deck](https://www.elgato.com/en/gaming/stream-deck). 256 | 257 | 258 | ### Matrix Multiplication 259 | 260 | Multiplying `u` and `v` is done via the expression `u * v`. Running `print("u * v: \(u * v)")` results in 261 | ``` 262 | u * v: 2x2-matrix: 263 | ⎛1.0i -2.0 + 2.0i⎞ 264 | ⎝3.0i -3.0 + 5.0i⎠ 265 | ``` 266 | 267 | Instead of `u′ * v` one can also use the equivalent, but faster expression `u ′* v`: 268 | ``` 269 | print("u′ * v: \(u′ * v)\n") 270 | print("u ′* v: \(u ′* v)\n") 271 | ``` 272 | yields 273 | ``` 274 | u′ * v: 2x2-matrix: 275 | ⎛1.0i 3.0 + 3.0i⎞ 276 | ⎝2.0 5.0 - 3.0i⎠ 277 | 278 | u ′* v: 2x2-matrix: 279 | ⎛1.0i 3.0 + 3.0i⎞ 280 | ⎝2.0 5.0 - 3.0i⎠ 281 | ``` 282 | Similarly, it is better to use `u *′ v` than `u * v′`, and `u ′*′ v` instead of `u′ * v′`. 283 | 284 | ### Vector Products 285 | 286 | We will view `u` and `v` as vectors `u.vector` and `v.vector` now, where `.vector` corresponds to a [*column-major*](https://en.wikipedia.org/wiki/Row-_and_column-major_order) order of the matrix elements: 287 | ``` 288 | u.vector: [1.0, 3.0, 2.0i, 1.0 + 4.0i] 289 | v.vector: [1.0i, 0.0, 0.0, 1.0 + 1.0i] 290 | ``` 291 | (Actually, in the above, we used `u.vector.toString()` and `v.vector.toString()` for better formatting of complex numbers. We will also do so below where appropriate without further mentioning it.) 292 | 293 | The dot product of `u.vector` and `v.vector` results in 294 | ``` 295 | u.vector * v.vector: -3.0 + 6.0i 296 | ``` 297 | Another vector product is 298 | ``` 299 | u.vector ′* v.vector: 5.0 - 2.0i 300 | ``` 301 | which corresponds to 302 | ``` 303 | u.vector′ * v.vector: [5.0 - 2.0i] 304 | ``` 305 | Furthermore, there is 306 | ``` 307 | u.vector *′ v.vector: 4x4-matrix: 308 | ⎛-1.0i 0.0 0.0 1.0 - 1.0i⎞ 309 | ⎜-3.0i 0.0 0.0 3.0 - 3.0i⎟ 310 | ⎜2.0 0.0 0.0 2.0 + 2.0i⎟ 311 | ⎝4.0 - 1.0i 0.0 0.0 5.0 + 3.0i⎠ 312 | ``` 313 | which is equivalent to 314 | ``` 315 | Matrix(u.vector) * v.vector′: 4x4-matrix: 316 | ⎛-1.0i 0.0 0.0 1.0 - 1.0i⎞ 317 | ⎜-3.0i 0.0 0.0 3.0 - 3.0i⎟ 318 | ⎜2.0 0.0 0.0 2.0 + 2.0i⎟ 319 | ⎝4.0 - 1.0i 0.0 0.0 5.0 + 3.0i⎠ 320 | ``` 321 | 322 | ### Element-wise Operations 323 | 324 | Element-wise operations like `.+`, `.-`, `.*` and `./` are supported on both vectors and matrices, for example: 325 | 326 | ``` 327 | u .* v : 2x2-matrix: 328 | ⎛1.0i 0.0 ⎞ 329 | ⎝0.0 -3.0 + 5.0i⎠ 330 | ``` 331 | 332 | ### Functional Operations 333 | 334 | The `Matrix` type supports functional operations like `map`, `reduce` and `combine`. These come in handy when performance is not that important, and there is no accelerated equivalent available (yet?). 335 | For example, the expression 336 | ```swift 337 | u.reduce(0) { x, y in max(x, y.magnitude) } 338 | ``` 339 | results in the value `4`. In this case it is better though to use the equivalent expression `u.infNorm` instead. 340 | 341 | ## Solving Linear Equations 342 | 343 | You can solve a system of linear equations like 344 | 345 | 1. 7x+5y-3z = 16 346 | 2. 3x-5y+2z = -8 347 | 3. 5x+3y-7z = 0 348 | 349 | by converting it into matrix form `A * u = b` and solving it for `u`: 350 | ```swift 351 | import LANumerics 352 | let A = Matrix(rows: [[7, 5, -3], [3, -5, 2], [5, 3, -7]]) 353 | let b : Vector = [16, -8, 0] 354 | let u = A.solve(b)! 355 | print("A: \(A)\n") 356 | print("b: \(b)\n") 357 | print("u: \(u.toString(precision: 1))") 358 | ``` 359 | This results in the output: 360 | ``` 361 | A: 3x3-matrix: 362 | ⎛7.0 5.0 -3.0⎞ 363 | ⎜3.0 -5.0 2.0 ⎟ 364 | ⎝5.0 3.0 -7.0⎠ 365 | 366 | b: [16.0, -8.0, 0.0] 367 | 368 | u: [1.0, 3.0, 2.0] 369 | ``` 370 | Therefore the solution is x=1, y=3, z=2. 371 | 372 | This example is actually plugged from an [article](https://www.appcoda.com/accelerate-framework/) which describes how to use the `Accelerate` framework directly and without a nice library like `LANumerics` 😁. 373 | 374 | You can solve for multiple right-hand sides simultaneously. For example, you can compute the inverse of `A` like so: 375 | ```swift 376 | let Id : Matrix = .eye(3) 377 | print("Id: \(Id)\n") 378 | let U = A.solve(Id)! 379 | print("U: \(U)\n") 380 | print("A * U: \(A * U)") 381 | ``` 382 | This results in the output 383 | ``` 384 | Id: 3x3-matrix: 385 | ⎛1.0 0.0 0.0⎞ 386 | ⎜0.0 1.0 0.0⎟ 387 | ⎝0.0 0.0 1.0⎠ 388 | 389 | U: 3x3-matrix: 390 | ⎛0.11328125 0.1015625 -0.019531249999999997⎞ 391 | ⎜0.12109375 -0.13281250000000003 -0.08984375 ⎟ 392 | ⎝0.1328125 0.01562499999999999 -0.1953125 ⎠ 393 | 394 | A * U: 3x3-matrix: 395 | ⎛1.0 -1.0755285551056204e-16 0.0⎞ 396 | ⎜0.0 1.0 0.0⎟ 397 | ⎝0.0 -4.163336342344337e-17 1.0⎠ 398 | ``` 399 | ## Linear Least Squares 400 | 401 | Extending the above example, you can also solve it using *least squares approximation* instead: 402 | ```swift 403 | print(A.solveLeastSquares(b)!.toString(precision: 1)) 404 | ``` 405 | results in the same solution `[1.0, 3.0, 2.0]`. 406 | 407 | Least squares is more general than solving linear equations directly, as it can also deal with situations where you have more equations than variables, or less equations than variables. In other words, it can also handle: 408 | * non-square matrices `A` 409 | * situations with large noise in the data 410 | * situations which are only approximately linear 411 | 412 | There is a shorthand notation available for the expression `A.solveLeastSquares(b)!`: 413 | ```swift 414 | A ∖ b 415 | ``` 416 | This also works for simultaneously solving for multiple right-hand sides as before, the inverse of `A` can therefore also be computed using the expression `A ∖ .eye(3)`: 417 | ``` 418 | A ∖ .eye(3): 3x3-matrix: 419 | ⎛0.11328124999999997 0.10156250000000001 -0.01953124999999994⎞ 420 | ⎜0.12109375 -0.13281250000000006 -0.08984374999999999⎟ 421 | ⎝0.13281249999999997 0.015624999999999993 -0.19531249999999994⎠ 422 | ``` 423 | Note that `∖` is the unicode character "Set Minus" `U+2216`. The same advice for smooth input of this character applies as for the input of `′` earlier. 424 | 425 | In addition, there is the operator `′∖` which combines taking the adjoint and solving via least squares. Therefore, to compute the inverse of `A′`, you could better write `A ′∖ .eye(3)` instead of `A′ ∖ .eye(3)`: 426 | ``` 427 | A ′∖ .eye(3): 3x3-matrix: 428 | ⎛0.11328124999999996 0.12109375 0.13281249999999994 ⎞ 429 | ⎜0.10156250000000001 -0.13281250000000003 0.01562499999999999 ⎟ 430 | ⎝-0.01953124999999994 -0.08984374999999999 -0.19531249999999994⎠ 431 | ``` 432 | 433 | The inverse of `A` can more concisely also be obtained via `A.inverse!`. 434 | 435 | ## Matrix Decompositions 436 | 437 | The following matrix decompositions are currently supported: 438 | 439 | * Singular value decomposition of a real or complex matrix `A`: 440 | ```swift 441 | A.svd() 442 | ``` 443 | * Eigen decomposition for self-adjoint matrices `A` (that is for real or complex matrices for which `A == A′`): 444 | ```swift 445 | A.eigen() 446 | ``` 447 | * Schur decomposition of a real or complex square-matrix `A`: 448 | ```swift 449 | A.schur() 450 | ``` 451 | 452 | 453 | -------------------------------------------------------------------------------- /Sources/LANumerics/AsPointer.swift: -------------------------------------------------------------------------------- 1 | func asMutablePointer(_ array : inout [T], block : (UnsafeMutablePointer) throws -> R) rethrows -> R { 2 | let count = array.count 3 | return try array.withUnsafeMutableBytes { ptr in 4 | try block(ptr.baseAddress!.bindMemory(to: T.self, capacity: count)) 5 | } 6 | } 7 | 8 | func asPointer(_ array : [T], block : (UnsafePointer) throws -> R) rethrows -> R { 9 | let count = array.count 10 | return try array.withUnsafeBytes { ptr in 11 | try block(ptr.baseAddress!.bindMemory(to: T.self, capacity: count)) 12 | } 13 | } 14 | 15 | -------------------------------------------------------------------------------- /Sources/LANumerics/Functional.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public extension Matrix { 4 | 5 | func map(_ transform : (Element) throws -> E) rethrows -> Matrix { 6 | return Matrix(rows: _rows, columns: _columns, elements: try elements.map(transform)) 7 | } 8 | 9 | func combine(_ other : Matrix, _ using : (Element, E) throws -> F) rethrows -> Matrix { 10 | precondition(hasSameDimensions(other)) 11 | let C = count 12 | var elems = [F](repeating: F.zero, count: C) 13 | try asPointer(self.elements) { elems1 in 14 | try asPointer(other.elements) { elems2 in 15 | try asMutablePointer(&elems) { elems in 16 | for i in 0 ..< C { 17 | elems[i] = try using(elems1[i], elems2[i]) 18 | } 19 | } 20 | } 21 | } 22 | return Matrix(rows: _rows, columns: _columns, elements: elems) 23 | } 24 | 25 | func reduce(_ start : F, _ using : (F, Element) throws -> F) rethrows -> F { 26 | var result = start 27 | for elem in elements { 28 | result = try using(result, elem) 29 | } 30 | return result 31 | } 32 | 33 | func reduce(_ using : (Element, Element) throws -> Element) rethrows -> Element { 34 | return try reduce(Element.zero, using) 35 | } 36 | 37 | func forall(_ cond : (Element) throws -> Bool) rethrows -> Bool { 38 | for elem in elements { 39 | guard try cond(elem) else { return false } 40 | } 41 | return true 42 | } 43 | 44 | func exists(_ cond : (Element) throws -> Bool) rethrows -> Bool { 45 | for elem in elements { 46 | if try cond(elem) { return true } 47 | } 48 | return false 49 | } 50 | 51 | 52 | } 53 | -------------------------------------------------------------------------------- /Sources/LANumerics/LANumeric+Complex.swift: -------------------------------------------------------------------------------- 1 | import Accelerate 2 | import Numerics 3 | 4 | fileprivate func recast(_ ptr : UnsafeMutablePointer) -> UnsafeMutablePointer { 5 | let p = UnsafeMutableRawPointer(ptr) 6 | return p.assumingMemoryBound(to: V.self) 7 | } 8 | 9 | fileprivate func recast(_ ptr : UnsafePointer) -> UnsafePointer { 10 | let p = UnsafeRawPointer(ptr) 11 | return p.assumingMemoryBound(to: V.self) 12 | } 13 | 14 | extension Complex { 15 | 16 | static func dispatch(float : () -> R, double : () -> R) -> R { 17 | if RealType.self == Float.self { 18 | return float() 19 | } else if RealType.self == Double.self { 20 | return double() 21 | } else { 22 | fatalError("cannot dispatch on Complex.RealType == \(RealType.self)") 23 | } 24 | } 25 | 26 | } 27 | 28 | extension Complex : MatrixElement { 29 | 30 | public var adjoint : Complex { return conjugate } 31 | 32 | } 33 | 34 | extension Complex : LANumeric, ExpressibleByFloatLiteral where RealType : LANumeric { 35 | 36 | public typealias FloatLiteralType = Double 37 | 38 | public init(floatLiteral: Self.FloatLiteralType) { 39 | var x : RealType = 0 40 | Complex.dispatch( 41 | float: { x = Float(floatLiteral) as! RealType }, 42 | double: { x = Double(floatLiteral) as! RealType } 43 | ) 44 | self.init(x) 45 | } 46 | 47 | public var manhattanLength : Magnitude { return real.magnitude + imaginary.magnitude } 48 | 49 | public init(magnitude: Self.Magnitude) { 50 | self = Complex(magnitude, 0) 51 | } 52 | 53 | public var toInt : Int { 54 | precondition(imaginary.isZero) 55 | return Complex.dispatch ( 56 | float: { return Int(real as! Float) }, 57 | double: { return Int(real as! Double) } 58 | ) 59 | } 60 | 61 | public static func random(in range: ClosedRange) -> Self { 62 | return Complex.dispatch ( 63 | float: { 64 | let r = range as! ClosedRange 65 | let x = Float.random(in: r) as! RealType 66 | let y = Float.random(in: r) as! RealType 67 | return Complex(x, y) 68 | }, 69 | double: { 70 | let r = range as! ClosedRange 71 | let x = Double.random(in: r) as! RealType 72 | let y = Double.random(in: r) as! RealType 73 | return Complex(x, y) 74 | } 75 | ) 76 | } 77 | 78 | public static func randomWhole(in range : ClosedRange) -> Self { 79 | return Complex.dispatch ( 80 | float: { 81 | let x = Float.randomWhole(in: range) as! RealType 82 | let y = Float.randomWhole(in: range) as! RealType 83 | return Complex(x, y) 84 | }, 85 | double: { 86 | let x = Double.randomWhole(in: range) as! RealType 87 | let y = Double.randomWhole(in: range) as! RealType 88 | return Complex(x, y) 89 | } 90 | ) 91 | } 92 | 93 | public static func blas_asum(_ N: Int32, _ X: UnsafePointer, _ incX: Int32) -> Self.Magnitude { 94 | return Complex.dispatch ( 95 | float: { cblas_scasum(N, X, incX) as! Self.Magnitude }, 96 | double: { cblas_dzasum(N, X, incX) as! Self.Magnitude } 97 | ) 98 | } 99 | 100 | public static func blas_nrm2(_ N: Int32, _ X: UnsafePointer, _ incX: Int32) -> Self.Magnitude { 101 | return Complex.dispatch ( 102 | float: { cblas_scnrm2(N, X, incX) as! Self.Magnitude }, 103 | double: { cblas_dznrm2(N, X, incX) as! Self.Magnitude } 104 | ) 105 | } 106 | 107 | public static func blas_scal(_ N : Int32, _ alpha : Self, _ X : UnsafeMutablePointer, _ incX : Int32) { 108 | var _alpha = alpha 109 | dispatch( 110 | float: { cblas_cscal(N, &_alpha, X, incX) }, 111 | double: { cblas_zscal(N, &_alpha, X, incX) } 112 | ) 113 | } 114 | 115 | public static func blas_axpby(_ N : Int32, _ alpha : Self, _ X : UnsafePointer, _ incX : Int32, _ beta : Self, _ Y : UnsafeMutablePointer, _ incY : Int32) { 116 | var _alpha = alpha 117 | var _beta = beta 118 | dispatch( 119 | float: { catlas_caxpby(N, &_alpha, X, incX, &_beta, Y, incY) }, 120 | double: { catlas_zaxpby(N, &_alpha, X, incX, &_beta, Y, incY) } 121 | ) 122 | } 123 | 124 | public static func blas_iamax(_ N : Int32, _ X : UnsafePointer, _ incX : Int32) -> Int32 { 125 | dispatch( 126 | float: { cblas_icamax(N, X, incX) }, 127 | double: { cblas_izamax(N, X, incX) } 128 | ) 129 | } 130 | 131 | public static func blas_iamax_inf(_ N : Int32, _ X : UnsafePointer, _ incX : Int32) -> Int32 { 132 | dispatch( 133 | float: { 134 | let R : UnsafePointer = recast(X) 135 | let I = R + 1 136 | let inc = 2 * incX 137 | let i1 = cblas_isamax(N, R, inc) 138 | let i2 = cblas_isamax(N, I, inc) 139 | let abs1 = abs(R[Int(2 * i1)]) 140 | let abs2 = abs(I[Int(2 * i2)]) 141 | if abs1 == abs2 { 142 | return min(i1, i2) 143 | } else if abs1 < abs2 { 144 | return i2 145 | } else { 146 | return i1 147 | } 148 | }, 149 | double: { 150 | let R : UnsafePointer = recast(X) 151 | let I = R + 1 152 | let inc = 2 * incX 153 | let i1 = cblas_idamax(N, R, inc) 154 | let i2 = cblas_idamax(N, I, inc) 155 | let abs1 = abs(R[Int(2 * i1)]) 156 | let abs2 = abs(I[Int(2 * i2)]) 157 | if abs1 == abs2 { 158 | return min(i1, i2) 159 | } else if abs1 < abs2 { 160 | return i2 161 | } else { 162 | return i1 163 | } 164 | } 165 | ) 166 | } 167 | 168 | public static func blas_dot(_ N : Int32, _ X : UnsafePointer, _ incX : Int32, _ Y : UnsafePointer, _ incY : Int32) -> Self { 169 | return dispatch( 170 | float: { 171 | var result : Self = 0 172 | cblas_cdotu_sub(N, X, incX, Y, incY, &result) 173 | return result 174 | }, 175 | double: { 176 | var result : Self = 0 177 | cblas_zdotu_sub(N, X, incX, Y, incY, &result) 178 | return result 179 | } 180 | ) 181 | } 182 | 183 | public static func blas_adjointDot(_ N : Int32, _ X : UnsafePointer, _ incX : Int32, _ Y : UnsafePointer, _ incY : Int32) -> Self { 184 | dispatch( 185 | float: { 186 | var result : Self = 0 187 | cblas_cdotc_sub(N, X, incX, Y, incY, &result) 188 | return result 189 | }, 190 | double: { 191 | var result : Self = 0 192 | cblas_zdotc_sub(N, X, incX, Y, incY, &result) 193 | return result 194 | } 195 | ) 196 | } 197 | 198 | public static func blas_gemm(_ Order : CBLAS_ORDER, _ TransA : CBLAS_TRANSPOSE, _ TransB : CBLAS_TRANSPOSE, 199 | _ M : Int32, _ N : Int32, _ K : Int32, 200 | _ alpha : Self, _ A : UnsafePointer, _ lda : Int32, _ B : UnsafePointer, _ ldb : Int32, 201 | _ beta : Self, _ C : UnsafeMutablePointer, _ ldc : Int32) 202 | { 203 | var _alpha = alpha 204 | var _beta = beta 205 | dispatch( 206 | float: { cblas_cgemm(Order, TransA, TransB, M, N, K, &_alpha, A, lda, B, ldb, &_beta, C, ldc) }, 207 | double: { cblas_zgemm(Order, TransA, TransB, M, N, K, &_alpha, A, lda, B, ldb, &_beta, C, ldc) } 208 | ) 209 | } 210 | 211 | public static func blas_gemv(_ Order : CBLAS_ORDER, _ TransA : CBLAS_TRANSPOSE, _ M : Int32, _ N : Int32, 212 | _ alpha : Self, _ A : UnsafePointer, _ lda : Int32, 213 | _ X : UnsafePointer, _ incX : Int32, 214 | _ beta : Self, _ Y : UnsafeMutablePointer, _ incY : Int32) 215 | { 216 | var _alpha = alpha 217 | var _beta = beta 218 | dispatch( 219 | float: { cblas_cgemv(Order, TransA, M, N, &_alpha, A, lda, X, incX, &_beta, Y, incY) }, 220 | double: { cblas_zgemv(Order, TransA, M, N, &_alpha, A, lda, X, incX, &_beta, Y, incY) } 221 | ) 222 | } 223 | 224 | public static func blas_ger(_ Order : CBLAS_ORDER, _ M : Int32, _ N : Int32, 225 | _ alpha : Self, _ X : UnsafePointer, _ incX : Int32, 226 | _ Y : UnsafePointer, _ incY : Int32, 227 | _ A : UnsafeMutablePointer, _ lda : Int32) 228 | { 229 | var _alpha = alpha 230 | dispatch( 231 | float: { cblas_cgeru(Order, M, N, &_alpha, X, incX, Y, incY, A, lda) }, 232 | double: { cblas_zgeru(Order, M, N, &_alpha, X, incX, Y, incY, A, lda) } 233 | ) 234 | } 235 | 236 | public static func blas_gerAdjoint(_ Order : CBLAS_ORDER, _ M : Int32, _ N : Int32, 237 | _ alpha : Self, _ X : UnsafePointer, _ incX : Int32, 238 | _ Y : UnsafePointer, _ incY : Int32, 239 | _ A : UnsafeMutablePointer, _ lda : Int32) 240 | { 241 | var _alpha = alpha 242 | dispatch( 243 | float: { cblas_cgerc(Order, M, N, &_alpha, X, incX, Y, incY, A, lda) }, 244 | double: { cblas_zgerc(Order, M, N, &_alpha, X, incX, Y, incY, A, lda) } 245 | ) 246 | } 247 | 248 | public static func lapack_gesv(_ n : UnsafeMutablePointer, _ nrhs : UnsafeMutablePointer, 249 | _ a : UnsafeMutablePointer, _ lda : UnsafeMutablePointer, 250 | _ ipiv : UnsafeMutablePointer, 251 | _ b : UnsafeMutablePointer, _ ldb : UnsafeMutablePointer, 252 | _ info : UnsafeMutablePointer) -> Int32 253 | { 254 | dispatch( 255 | float: { cgesv_(n, nrhs, recast(a), lda, ipiv, recast(b), ldb, info) }, 256 | double: { zgesv_(n, nrhs, recast(a), lda, ipiv, recast(b), ldb, info) } 257 | ) 258 | } 259 | 260 | public static func lapack_gels(_ trans : Transpose, 261 | _ m : UnsafeMutablePointer, _ n : UnsafeMutablePointer, _ nrhs : UnsafeMutablePointer, 262 | _ a : UnsafeMutablePointer, _ lda : UnsafeMutablePointer, 263 | _ b : UnsafeMutablePointer, _ ldb : UnsafeMutablePointer, 264 | _ work : UnsafeMutablePointer, _ lwork : UnsafeMutablePointer, 265 | _ info : UnsafeMutablePointer) -> Int32 266 | { 267 | var trans = trans.blas(complex: true) 268 | return dispatch( 269 | float: { cgels_(&trans, m, n, nrhs, recast(a), lda, recast(b), ldb, recast(work), lwork, info) }, 270 | double: { zgels_(&trans, m, n, nrhs, recast(a), lda, recast(b), ldb, recast(work), lwork, info) } 271 | ) 272 | } 273 | 274 | public static func lapack_gesvd(_ jobu : UnsafeMutablePointer, _ jobvt : UnsafeMutablePointer, 275 | _ m : UnsafeMutablePointer, _ n : UnsafeMutablePointer, 276 | _ a : UnsafeMutablePointer, _ lda : UnsafeMutablePointer, 277 | _ s : UnsafeMutablePointer, 278 | _ u : UnsafeMutablePointer, _ ldu : UnsafeMutablePointer, 279 | _ vt : UnsafeMutablePointer, _ ldvt : UnsafeMutablePointer, 280 | _ work : UnsafeMutablePointer, _ lwork : UnsafeMutablePointer, 281 | _ info : UnsafeMutablePointer) -> Int32 282 | { 283 | return dispatch( 284 | float: { 285 | var rwork = [Float](repeating: 0, count: 5*Int(min(m.pointee, n.pointee))) 286 | return cgesvd_(jobu, jobvt, m, n, recast(a), lda, recast(s), recast(u), ldu, recast(vt), ldvt, recast(work), lwork, &rwork, info) 287 | }, 288 | double: { 289 | var rwork = [Double](repeating: 0, count: 5*Int(min(m.pointee, n.pointee))) 290 | return zgesvd_(jobu, jobvt, m, n, recast(a), lda, recast(s), recast(u), ldu, recast(vt), ldvt, recast(work), lwork, &rwork, info) 291 | } 292 | ) 293 | } 294 | 295 | public static func lapack_heev(_ jobz : UnsafeMutablePointer, _ uplo : UnsafeMutablePointer, _ n : UnsafeMutablePointer, 296 | _ a : UnsafeMutablePointer, _ lda : UnsafeMutablePointer, 297 | _ w : UnsafeMutablePointer, 298 | _ work : UnsafeMutablePointer, _ lwork : UnsafeMutablePointer, 299 | _ info : UnsafeMutablePointer) -> Int32 300 | { 301 | var rwork : [Self.Magnitude] = Array(repeating: 0, count: max(1, 3*Int(n.pointee)-2)) 302 | return dispatch( 303 | float: { cheev_(jobz, uplo, n, recast(a), lda, recast(w), recast(work), lwork, recast(&rwork), info) }, 304 | double: { zheev_(jobz, uplo, n, recast(a), lda, recast(w), recast(work), lwork, recast(&rwork), info) } 305 | ) 306 | } 307 | 308 | public static func lapack_gees(_ jobvs : UnsafeMutablePointer, _ n : UnsafeMutablePointer, 309 | _ a : UnsafeMutablePointer, _ lda : UnsafeMutablePointer, 310 | _ wr : UnsafeMutablePointer, 311 | _ wi : UnsafeMutablePointer, 312 | _ vs : UnsafeMutablePointer, _ ldvs : UnsafeMutablePointer, 313 | _ work : UnsafeMutablePointer, _ lwork : UnsafeMutablePointer, 314 | _ info : UnsafeMutablePointer) -> Int32 315 | { 316 | let N = Int(n.pointee) 317 | var rwork : [Self.Magnitude] = Array(repeating: 0, count: N) 318 | var sort : Int8 = 0x4E /* "N" */ 319 | var sdim : IntLA = 0 320 | var w : [Self] = Array(repeating: 0, count: N) 321 | let result = dispatch( 322 | float: { cgees_(jobvs, &sort, nil, n, recast(a), lda , &sdim, recast(&w), recast(vs), ldvs, recast(work), lwork, recast(&rwork), nil, info) }, 323 | double: { zgees_(jobvs, &sort, nil, n, recast(a), lda , &sdim, recast(&w), recast(vs), ldvs, recast(work), lwork, recast(&rwork), nil, info) } 324 | ) 325 | for i in 0 ..< N { 326 | wr[i] = w[i].real 327 | wi[i] = w[i].imaginary 328 | } 329 | return result 330 | } 331 | 332 | public static func vDSP_convert(interleavedComplex : [Self]) -> (real: [Self.Magnitude], imaginary: [Self.Magnitude]) { 333 | let N = vDSP_Length(interleavedComplex.count) 334 | var real: [Self.Magnitude] = Array(repeating: 0, count: Int(N)) 335 | var imaginary: [Self.Magnitude] = Array(repeating: 0, count: Int(N)) 336 | dispatch( 337 | float: { 338 | var split = DSPSplitComplex(realp: recast(&real), imagp: recast(&imaginary)) 339 | vDSP_ctoz(recast(interleavedComplex), 2, &split, 1, N) 340 | }, 341 | double: { 342 | var split = DSPDoubleSplitComplex(realp: recast(&real), imagp: recast(&imaginary)) 343 | vDSP_ctozD(recast(interleavedComplex), 2, &split, 1, N) 344 | } 345 | ) 346 | return (real: real, imaginary: imaginary) 347 | } 348 | 349 | public static func vDSP_convert(real: [Self.Magnitude], imaginary: [Self.Magnitude]) -> [Self] { 350 | precondition(real.count == imaginary.count) 351 | let N = vDSP_Length(real.count) 352 | var result : [Self] = Array(repeating: 0, count: Int(N)) 353 | dispatch( 354 | float: { 355 | var real = real 356 | var imaginary = imaginary 357 | var split = DSPSplitComplex(realp: recast(&real), imagp: recast(&imaginary)) 358 | vDSP_ztoc(&split, 1, recast(&result), 2, N) 359 | }, 360 | double: { 361 | var real = real 362 | var imaginary = imaginary 363 | var split = DSPDoubleSplitComplex(realp: recast(&real), imagp: recast(&imaginary)) 364 | vDSP_ztocD(&split, 1, recast(&result), 2, N) 365 | } 366 | ) 367 | return result 368 | } 369 | 370 | public static func vDSP_elementwise_absolute(_ v : [Self]) -> [Self.Magnitude] { 371 | var (real, imaginary) = vDSP_convert(interleavedComplex: v) 372 | let N = vDSP_Length(v.count) 373 | var result: [Self.Magnitude] = Array(repeating: 0, count: Int(N)) 374 | dispatch ( 375 | float: { 376 | var split = DSPSplitComplex(realp: recast(&real), imagp: recast(&imaginary)) 377 | vDSP_zvabs(&split, 1, recast(&result), 1, N) 378 | }, 379 | double: { 380 | var split = DSPDoubleSplitComplex(realp: recast(&real), imagp: recast(&imaginary)) 381 | vDSP_zvabsD(&split, 1, recast(&result), 1, N) 382 | } 383 | ) 384 | return result 385 | } 386 | 387 | public static func vDSP_elementwise_adjoint(_ v : [Self]) -> [Self] { 388 | var (real, imaginary) = vDSP_convert(interleavedComplex: v) 389 | let N = vDSP_Length(v.count) 390 | var target_real : [Self.Magnitude] = Array(repeating: 0, count: Int(N)) 391 | var target_imaginary : [Self.Magnitude] = Array(repeating: 0, count: Int(N)) 392 | dispatch( 393 | float: { 394 | var source_split = DSPSplitComplex(realp: recast(&real), imagp: recast(&imaginary)) 395 | var target_split = DSPSplitComplex(realp: recast(&target_real), imagp: recast(&target_imaginary)) 396 | vDSP_zvconj(&source_split, 1, &target_split, 1, N) 397 | }, 398 | double: { 399 | var source_split = DSPDoubleSplitComplex(realp: recast(&real), imagp: recast(&imaginary)) 400 | var target_split = DSPDoubleSplitComplex(realp: recast(&target_real), imagp: recast(&target_imaginary)) 401 | vDSP_zvconjD(&source_split, 1, &target_split, 1, N) 402 | } 403 | ) 404 | return vDSP_convert(real: target_real, imaginary: target_imaginary) 405 | } 406 | 407 | public static func vDSP_elementwise_multiply(_ u : [Self], _ v : [Self]) -> [Self] { 408 | let N = u.count 409 | precondition(N == v.count) 410 | var (real_u, imaginary_u) = vDSP_convert(interleavedComplex: u) 411 | var (real_v, imaginary_v) = vDSP_convert(interleavedComplex: v) 412 | var target_real : [Self.Magnitude] = Array(repeating: 0, count: N) 413 | var target_imaginary : [Self.Magnitude] = Array(repeating: 0, count: N) 414 | dispatch( 415 | float: { 416 | var split_u = DSPSplitComplex(realp: recast(&real_u), imagp: recast(&imaginary_u)) 417 | var split_v = DSPSplitComplex(realp: recast(&real_v), imagp: recast(&imaginary_v)) 418 | var target_split = DSPSplitComplex(realp: recast(&target_real), imagp: recast(&target_imaginary)) 419 | vDSP_zvmul(&split_u, 1, &split_v, 1, &target_split, 1, vDSP_Length(N), 1) 420 | }, 421 | double: { 422 | var split_u = DSPDoubleSplitComplex(realp: recast(&real_u), imagp: recast(&imaginary_u)) 423 | var split_v = DSPDoubleSplitComplex(realp: recast(&real_v), imagp: recast(&imaginary_v)) 424 | var target_split = DSPDoubleSplitComplex(realp: recast(&target_real), imagp: recast(&target_imaginary)) 425 | vDSP_zvmulD(&split_u, 1, &split_v, 1, &target_split, 1, vDSP_Length(N), 1) 426 | } 427 | ) 428 | return vDSP_convert(real: target_real, imaginary: target_imaginary) 429 | } 430 | 431 | public static func vDSP_elementwise_divide(_ u : [Self], _ v : [Self]) -> [Self] { 432 | let N = u.count 433 | precondition(N == v.count) 434 | var (real_u, imaginary_u) = vDSP_convert(interleavedComplex: u) 435 | var (real_v, imaginary_v) = vDSP_convert(interleavedComplex: v) 436 | var target_real : [Self.Magnitude] = Array(repeating: 0, count: N) 437 | var target_imaginary : [Self.Magnitude] = Array(repeating: 0, count: N) 438 | dispatch( 439 | float: { 440 | var split_u = DSPSplitComplex(realp: recast(&real_u), imagp: recast(&imaginary_u)) 441 | var split_v = DSPSplitComplex(realp: recast(&real_v), imagp: recast(&imaginary_v)) 442 | var target_split = DSPSplitComplex(realp: recast(&target_real), imagp: recast(&target_imaginary)) 443 | vDSP_zvdiv(&split_v, 1, &split_u, 1, &target_split, 1, vDSP_Length(N)) 444 | }, 445 | double: { 446 | var split_u = DSPDoubleSplitComplex(realp: recast(&real_u), imagp: recast(&imaginary_u)) 447 | var split_v = DSPDoubleSplitComplex(realp: recast(&real_v), imagp: recast(&imaginary_v)) 448 | var target_split = DSPDoubleSplitComplex(realp: recast(&target_real), imagp: recast(&target_imaginary)) 449 | vDSP_zvdivD(&split_v, 1, &split_u, 1, &target_split, 1, vDSP_Length(N)) 450 | } 451 | ) 452 | return vDSP_convert(real: target_real, imaginary: target_imaginary) 453 | } 454 | 455 | } 456 | 457 | -------------------------------------------------------------------------------- /Sources/LANumerics/LANumeric+Double.swift: -------------------------------------------------------------------------------- 1 | import Accelerate 2 | import Numerics 3 | 4 | extension Double : LANumeric { 5 | 6 | public var manhattanLength : Double { return magnitude } 7 | 8 | public var adjoint : Double { return self } 9 | 10 | public var length : Self.Magnitude { return magnitude } 11 | 12 | public var lengthSquared : Self.Magnitude { return magnitude * magnitude } 13 | 14 | public var toInt : Int { 15 | return Int(self) 16 | } 17 | 18 | public init(magnitude: Self.Magnitude) { 19 | self = magnitude 20 | } 21 | 22 | public static func randomWhole(in range : ClosedRange) -> Self { 23 | return Double(Int.random(in: range)) 24 | } 25 | 26 | public static func blas_asum(_ N: Int32, _ X: UnsafePointer, _ incX: Int32) -> Self.Magnitude { 27 | return cblas_dasum(N, X, incX) 28 | } 29 | 30 | public static func blas_nrm2(_ N: Int32, _ X: UnsafePointer, _ incX: Int32) -> Self.Magnitude { 31 | return cblas_dnrm2(N, X, incX) 32 | } 33 | 34 | public static func blas_scal(_ N : Int32, _ alpha : Self, _ X : UnsafeMutablePointer, _ incX : Int32) { 35 | cblas_dscal(N, alpha, X, incX) 36 | } 37 | 38 | public static func blas_axpby(_ N : Int32, _ alpha : Self, _ X : UnsafePointer, _ incX : Int32, _ beta : Self, _ Y : UnsafeMutablePointer, _ incY : Int32) { 39 | catlas_daxpby(N, alpha, X, incX, beta, Y, incY) 40 | } 41 | 42 | public static func blas_iamax(_ N : Int32, _ X : UnsafePointer, _ incX : Int32) -> Int32 { 43 | cblas_idamax(N, X, incX) 44 | } 45 | 46 | public static func blas_iamax_inf(_ N : Int32, _ X : UnsafePointer, _ incX : Int32) -> Int32 { 47 | cblas_idamax(N, X, incX) 48 | } 49 | 50 | public static func blas_dot(_ N : Int32, _ X : UnsafePointer, _ incX : Int32, _ Y : UnsafePointer, _ incY : Int32) -> Self { 51 | cblas_ddot(N, X, incX, Y, incY) 52 | } 53 | 54 | public static func blas_adjointDot(_ N : Int32, _ X : UnsafePointer, _ incX : Int32, _ Y : UnsafePointer, _ incY : Int32) -> Self { 55 | cblas_ddot(N, X, incX, Y, incY) 56 | } 57 | 58 | public static func blas_gemm(_ Order : CBLAS_ORDER, _ TransA : CBLAS_TRANSPOSE, _ TransB : CBLAS_TRANSPOSE, 59 | _ M : Int32, _ N : Int32, _ K : Int32, 60 | _ alpha : Self, _ A : UnsafePointer, _ lda : Int32, _ B : UnsafePointer, _ ldb : Int32, 61 | _ beta : Self, _ C : UnsafeMutablePointer, _ ldc : Int32) 62 | { 63 | cblas_dgemm(Order, TransA, TransB, M, N, K, alpha, A, lda, B, ldb, beta, C, ldc) 64 | } 65 | 66 | public static func blas_gemv(_ Order : CBLAS_ORDER, _ TransA : CBLAS_TRANSPOSE, _ M : Int32, _ N : Int32, 67 | _ alpha : Self, _ A : UnsafePointer, _ lda : Int32, 68 | _ X : UnsafePointer, _ incX : Int32, 69 | _ beta : Self, _ Y : UnsafeMutablePointer, _ incY : Int32) 70 | { 71 | cblas_dgemv(Order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY) 72 | } 73 | 74 | public static func blas_ger(_ Order : CBLAS_ORDER, _ M : Int32, _ N : Int32, 75 | _ alpha : Self, _ X : UnsafePointer, _ incX : Int32, 76 | _ Y : UnsafePointer, _ incY : Int32, 77 | _ A : UnsafeMutablePointer, _ lda : Int32) 78 | { 79 | cblas_dger(Order, M, N, alpha, X, incX, Y, incY, A, lda) 80 | } 81 | 82 | public static func blas_gerAdjoint(_ Order : CBLAS_ORDER, _ M : Int32, _ N : Int32, 83 | _ alpha : Self, _ X : UnsafePointer, _ incX : Int32, 84 | _ Y : UnsafePointer, _ incY : Int32, 85 | _ A : UnsafeMutablePointer, _ lda : Int32) 86 | { 87 | cblas_dger(Order, M, N, alpha, X, incX, Y, incY, A, lda) 88 | } 89 | 90 | 91 | public static func lapack_gesv(_ n : UnsafeMutablePointer, _ nrhs : UnsafeMutablePointer, 92 | _ a : UnsafeMutablePointer, _ lda : UnsafeMutablePointer, 93 | _ ipiv : UnsafeMutablePointer, 94 | _ b : UnsafeMutablePointer, _ ldb : UnsafeMutablePointer, 95 | _ info : UnsafeMutablePointer) -> Int32 96 | { 97 | dgesv_(n, nrhs, a, lda, ipiv, b, ldb, info) 98 | } 99 | 100 | public static func lapack_gels(_ trans : Transpose, 101 | _ m : UnsafeMutablePointer, _ n : UnsafeMutablePointer, _ nrhs : UnsafeMutablePointer, 102 | _ a : UnsafeMutablePointer, _ lda : UnsafeMutablePointer, 103 | _ b : UnsafeMutablePointer, _ ldb : UnsafeMutablePointer, 104 | _ work : UnsafeMutablePointer, _ lwork : UnsafeMutablePointer, 105 | _ info : UnsafeMutablePointer) -> Int32 106 | { 107 | var trans : Int8 = trans.blas(complex: false) 108 | return dgels_(&trans, m, n, nrhs, a, lda, b, ldb, work, lwork, info) 109 | } 110 | 111 | public static func lapack_gesvd(_ jobu : UnsafeMutablePointer, _ jobvt : UnsafeMutablePointer, 112 | _ m : UnsafeMutablePointer, _ n : UnsafeMutablePointer, 113 | _ a : UnsafeMutablePointer, _ lda : UnsafeMutablePointer, 114 | _ s : UnsafeMutablePointer, 115 | _ u : UnsafeMutablePointer, _ ldu : UnsafeMutablePointer, 116 | _ vt : UnsafeMutablePointer, _ ldvt : UnsafeMutablePointer, 117 | _ work : UnsafeMutablePointer, _ lwork : UnsafeMutablePointer, 118 | _ info : UnsafeMutablePointer) -> Int32 119 | { 120 | dgesvd_(jobu, jobvt, m, n, a, lda, s, u, ldu, vt, ldvt, work, lwork, info) 121 | } 122 | 123 | public static func lapack_heev(_ jobz : UnsafeMutablePointer, _ uplo : UnsafeMutablePointer, _ n : UnsafeMutablePointer, 124 | _ a : UnsafeMutablePointer, _ lda : UnsafeMutablePointer, 125 | _ w : UnsafeMutablePointer, 126 | _ work : UnsafeMutablePointer, _ lwork : UnsafeMutablePointer, 127 | _ info : UnsafeMutablePointer) -> Int32 128 | { 129 | dsyev_(jobz, uplo, n, a, lda, w, work, lwork, info) 130 | } 131 | 132 | public static func lapack_gees(_ jobvs : UnsafeMutablePointer, _ n : UnsafeMutablePointer, 133 | _ a : UnsafeMutablePointer, _ lda : UnsafeMutablePointer, 134 | _ wr : UnsafeMutablePointer, 135 | _ wi : UnsafeMutablePointer, 136 | _ vs : UnsafeMutablePointer, _ ldvs : UnsafeMutablePointer, 137 | _ work : UnsafeMutablePointer, _ lwork : UnsafeMutablePointer, 138 | _ info : UnsafeMutablePointer) -> Int32 139 | { 140 | var sort : Int8 = 0x4E /* "N" */ 141 | var sdim : IntLA = 0 142 | return dgees_(jobvs, &sort, nil, n, a, lda , &sdim, wr, wi, vs, ldvs, work, lwork, nil, info) 143 | } 144 | 145 | public static func vDSP_elementwise_absolute(_ v : [Self]) -> [Self.Magnitude] { 146 | var result : [Self] = Array(repeating: 0, count: v.count) 147 | vDSP_vabsD(v, 1, &result, 1, vDSP_Length(v.count)) 148 | return result 149 | } 150 | 151 | public static func vDSP_elementwise_adjoint(_ v : [Self]) -> [Self] { 152 | return v 153 | } 154 | 155 | public static func vDSP_elementwise_multiply(_ u : [Self], _ v : [Self]) -> [Self] { 156 | let N = u.count 157 | precondition(N == v.count) 158 | var result : [Self] = Array(repeating: 0, count: N) 159 | vDSP_vmulD(u, 1, v, 1, &result, 1, vDSP_Length(N)) 160 | return result 161 | } 162 | 163 | public static func vDSP_elementwise_divide(_ u : [Self], _ v : [Self]) -> [Self] { 164 | let N = u.count 165 | precondition(N == v.count) 166 | var result : [Self] = Array(repeating: 0, count: N) 167 | vDSP_vdivD(v, 1, u, 1, &result, 1, vDSP_Length(N)) 168 | return result 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /Sources/LANumerics/LANumeric+Float.swift: -------------------------------------------------------------------------------- 1 | import Accelerate 2 | import Numerics 3 | 4 | extension Float : LANumeric { 5 | 6 | public var manhattanLength : Float { return magnitude } 7 | 8 | public var adjoint : Float { return self } 9 | 10 | public var length : Self.Magnitude { return magnitude } 11 | 12 | public var lengthSquared : Self.Magnitude { return magnitude * magnitude } 13 | 14 | public var toInt : Int { 15 | return Int(self) 16 | } 17 | 18 | public init(magnitude: Self.Magnitude) { 19 | self = magnitude 20 | } 21 | 22 | public static func randomWhole(in range : ClosedRange) -> Self { 23 | return Float(Int.random(in: range)) 24 | } 25 | 26 | public static func blas_asum(_ N: Int32, _ X: UnsafePointer, _ incX: Int32) -> Self.Magnitude { 27 | return cblas_sasum(N, X, incX) 28 | } 29 | 30 | public static func blas_nrm2(_ N: Int32, _ X: UnsafePointer, _ incX: Int32) -> Self.Magnitude { 31 | return cblas_snrm2(N, X, incX) 32 | } 33 | 34 | public static func blas_scal(_ N : Int32, _ alpha : Self, _ X : UnsafeMutablePointer, _ incX : Int32) { 35 | cblas_sscal(N, alpha, X, incX) 36 | } 37 | 38 | public static func blas_axpby(_ N : Int32, _ alpha : Self, _ X : UnsafePointer, _ incX : Int32, _ beta : Self, _ Y : UnsafeMutablePointer, _ incY : Int32) { 39 | catlas_saxpby(N, alpha, X, incX, beta, Y, incY) 40 | } 41 | 42 | public static func blas_iamax(_ N : Int32, _ X : UnsafePointer, _ incX : Int32) -> Int32 { 43 | cblas_isamax(N, X, incX) 44 | } 45 | 46 | public static func blas_iamax_inf(_ N : Int32, _ X : UnsafePointer, _ incX : Int32) -> Int32 { 47 | cblas_isamax(N, X, incX) 48 | } 49 | 50 | public static func blas_dot(_ N : Int32, _ X : UnsafePointer, _ incX : Int32, _ Y : UnsafePointer, _ incY : Int32) -> Self { 51 | cblas_sdot(N, X, incX, Y, incY) 52 | } 53 | 54 | public static func blas_adjointDot(_ N : Int32, _ X : UnsafePointer, _ incX : Int32, _ Y : UnsafePointer, _ incY : Int32) -> Self { 55 | cblas_sdot(N, X, incX, Y, incY) 56 | } 57 | 58 | public static func blas_gemm(_ Order : CBLAS_ORDER, _ TransA : CBLAS_TRANSPOSE, _ TransB : CBLAS_TRANSPOSE, 59 | _ M : Int32, _ N : Int32, _ K : Int32, 60 | _ alpha : Self, _ A : UnsafePointer, _ lda : Int32, _ B : UnsafePointer, _ ldb : Int32, 61 | _ beta : Self, _ C : UnsafeMutablePointer, _ ldc : Int32) 62 | { 63 | cblas_sgemm(Order, TransA, TransB, M, N, K, alpha, A, lda, B, ldb, beta, C, ldc) 64 | } 65 | 66 | public static func blas_gemv(_ Order : CBLAS_ORDER, _ TransA : CBLAS_TRANSPOSE, _ M : Int32, _ N : Int32, 67 | _ alpha : Self, _ A : UnsafePointer, _ lda : Int32, 68 | _ X : UnsafePointer, _ incX : Int32, 69 | _ beta : Self, _ Y : UnsafeMutablePointer, _ incY : Int32) 70 | { 71 | cblas_sgemv(Order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY) 72 | } 73 | 74 | public static func blas_ger(_ Order : CBLAS_ORDER, _ M : Int32, _ N : Int32, 75 | _ alpha : Self, _ X : UnsafePointer, _ incX : Int32, 76 | _ Y : UnsafePointer, _ incY : Int32, 77 | _ A : UnsafeMutablePointer, _ lda : Int32) 78 | { 79 | cblas_sger(Order, M, N, alpha, X, incX, Y, incY, A, lda) 80 | } 81 | 82 | public static func blas_gerAdjoint(_ Order : CBLAS_ORDER, _ M : Int32, _ N : Int32, 83 | _ alpha : Self, _ X : UnsafePointer, _ incX : Int32, 84 | _ Y : UnsafePointer, _ incY : Int32, 85 | _ A : UnsafeMutablePointer, _ lda : Int32) 86 | { 87 | cblas_sger(Order, M, N, alpha, X, incX, Y, incY, A, lda) 88 | } 89 | 90 | public static func lapack_gesv(_ n : UnsafeMutablePointer, _ nrhs : UnsafeMutablePointer, 91 | _ a : UnsafeMutablePointer, _ lda : UnsafeMutablePointer, 92 | _ ipiv : UnsafeMutablePointer, 93 | _ b : UnsafeMutablePointer, _ ldb : UnsafeMutablePointer, 94 | _ info : UnsafeMutablePointer) -> Int32 95 | { 96 | sgesv_(n, nrhs, a, lda, ipiv, b, ldb, info) 97 | } 98 | 99 | public static func lapack_gels(_ trans : Transpose, 100 | _ m : UnsafeMutablePointer, _ n : UnsafeMutablePointer, _ nrhs : UnsafeMutablePointer, 101 | _ a : UnsafeMutablePointer, _ lda : UnsafeMutablePointer, 102 | _ b : UnsafeMutablePointer, _ ldb : UnsafeMutablePointer, 103 | _ work : UnsafeMutablePointer, _ lwork : UnsafeMutablePointer, 104 | _ info : UnsafeMutablePointer) -> Int32 105 | { 106 | var trans : Int8 = trans.blas(complex: false) 107 | return sgels_(&trans, m, n, nrhs, a, lda, b, ldb, work, lwork, info) 108 | } 109 | 110 | public static func lapack_gesvd(_ jobu : UnsafeMutablePointer, _ jobvt : UnsafeMutablePointer, 111 | _ m : UnsafeMutablePointer, _ n : UnsafeMutablePointer, 112 | _ a : UnsafeMutablePointer, _ lda : UnsafeMutablePointer, 113 | _ s : UnsafeMutablePointer, 114 | _ u : UnsafeMutablePointer, _ ldu : UnsafeMutablePointer, 115 | _ vt : UnsafeMutablePointer, _ ldvt : UnsafeMutablePointer, 116 | _ work : UnsafeMutablePointer, _ lwork : UnsafeMutablePointer, 117 | _ info : UnsafeMutablePointer) -> Int32 118 | { 119 | sgesvd_(jobu, jobvt, m, n, a, lda, s, u, ldu, vt, ldvt, work, lwork, info) 120 | } 121 | 122 | public static func lapack_heev(_ jobz : UnsafeMutablePointer, _ uplo : UnsafeMutablePointer, _ n : UnsafeMutablePointer, 123 | _ a : UnsafeMutablePointer, _ lda : UnsafeMutablePointer, 124 | _ w : UnsafeMutablePointer, 125 | _ work : UnsafeMutablePointer, _ lwork : UnsafeMutablePointer, 126 | _ info : UnsafeMutablePointer) -> Int32 127 | { 128 | ssyev_(jobz, uplo, n, a, lda, w, work, lwork, info) 129 | } 130 | 131 | public static func lapack_gees(_ jobvs : UnsafeMutablePointer, _ n : UnsafeMutablePointer, 132 | _ a : UnsafeMutablePointer, _ lda : UnsafeMutablePointer, 133 | _ wr : UnsafeMutablePointer, 134 | _ wi : UnsafeMutablePointer, 135 | _ vs : UnsafeMutablePointer, _ ldvs : UnsafeMutablePointer, 136 | _ work : UnsafeMutablePointer, _ lwork : UnsafeMutablePointer, 137 | _ info : UnsafeMutablePointer) -> Int32 138 | { 139 | var sort : Int8 = 0x4E /* "N" */ 140 | var sdim : IntLA = 0 141 | return sgees_(jobvs, &sort, nil, n, a, lda , &sdim, wr, wi, vs, ldvs, work, lwork, nil, info) 142 | } 143 | 144 | public static func vDSP_elementwise_absolute(_ v : [Self]) -> [Self.Magnitude] { 145 | var result : [Self.Magnitude] = Array(repeating: 0, count: v.count) 146 | vDSP_vabs(v, 1, &result, 1, vDSP_Length(v.count)) 147 | return result 148 | } 149 | 150 | public static func vDSP_elementwise_adjoint(_ v : [Self]) -> [Self] { 151 | return v 152 | } 153 | 154 | public static func vDSP_elementwise_multiply(_ u : [Self], _ v : [Self]) -> [Self] { 155 | let N = u.count 156 | precondition(N == v.count) 157 | var result : [Self] = Array(repeating: 0, count: N) 158 | vDSP_vmul(u, 1, v, 1, &result, 1, vDSP_Length(N)) 159 | return result 160 | } 161 | 162 | public static func vDSP_elementwise_divide(_ u : [Self], _ v : [Self]) -> [Self] { 163 | let N = u.count 164 | precondition(N == v.count) 165 | var result : [Self] = Array(repeating: 0, count: N) 166 | vDSP_vdiv(v, 1, u, 1, &result, 1, vDSP_Length(N)) 167 | return result 168 | } 169 | 170 | } 171 | -------------------------------------------------------------------------------- /Sources/LANumerics/LANumeric.swift: -------------------------------------------------------------------------------- 1 | import Accelerate 2 | import Numerics 3 | 4 | public enum SVDJob { 5 | case all 6 | case singular 7 | case none 8 | 9 | var lapackJob : Int8 { 10 | switch self { 11 | case .all: return 0x41 /* "A" */ 12 | case .singular: return 0x53 /* "S" */ 13 | case .none: return 0x4E /* "N" */ 14 | } 15 | } 16 | } 17 | 18 | public enum Transpose { 19 | case none 20 | case transpose 21 | case adjoint 22 | 23 | internal func blas(complex: Bool) -> Int8 { 24 | switch self { 25 | case .none: return 0x4E /* "N" */ 26 | case .transpose: return 0x54 /* "T" */ 27 | case .adjoint where complex: return 0x43 /* "C" */ 28 | case .adjoint: return 0x54 /* "T" */ 29 | } 30 | } 31 | 32 | internal var cblas : CBLAS_TRANSPOSE { 33 | switch self { 34 | case .none: return CblasNoTrans 35 | case .transpose: return CblasTrans 36 | case .adjoint: return CblasConjTrans 37 | } 38 | } 39 | 40 | public func apply(_ matrix : Matrix) -> Matrix { 41 | switch self { 42 | case .none: return matrix 43 | case .transpose: return matrix.transpose 44 | case .adjoint: return matrix.adjoint 45 | } 46 | } 47 | } 48 | 49 | public protocol LANumeric : MatrixElement, AlgebraicField, ExpressibleByFloatLiteral where Magnitude : LANumeric { 50 | 51 | typealias IntLA = __CLPK_integer 52 | 53 | init(magnitude : Self.Magnitude) 54 | 55 | var manhattanLength : Self.Magnitude { get } 56 | 57 | var length : Self.Magnitude { get } 58 | 59 | var lengthSquared : Self.Magnitude { get } 60 | 61 | var toInt : Int { get } 62 | 63 | static func random(in : ClosedRange) -> Self 64 | 65 | static func randomWhole(in : ClosedRange) -> Self 66 | 67 | static func blas_asum(_ N : Int32, _ X : UnsafePointer, _ incX : Int32) -> Self.Magnitude 68 | 69 | static func blas_nrm2(_ N : Int32, _ X : UnsafePointer, _ incX : Int32) -> Self.Magnitude 70 | 71 | static func blas_scal(_ N : Int32, _ alpha : Self, _ X : UnsafeMutablePointer, _ incX : Int32) 72 | 73 | static func blas_axpby(_ N : Int32, 74 | _ alpha : Self, _ X : UnsafePointer, _ incX : Int32, 75 | _ beta : Self, _ Y : UnsafeMutablePointer, _ incY : Int32) 76 | 77 | static func blas_iamax(_ N : Int32, 78 | _ X : UnsafePointer, _ incX : Int32) -> Int32 79 | 80 | static func blas_iamax_inf(_ N : Int32, 81 | _ X : UnsafePointer, _ incX : Int32) -> Int32 82 | 83 | static func blas_dot(_ N : Int32, 84 | _ X : UnsafePointer, _ incX : Int32, 85 | _ Y : UnsafePointer, _ incY : Int32) -> Self 86 | 87 | static func blas_adjointDot(_ N : Int32, _ X : UnsafePointer, _ incX : Int32, _ Y : UnsafePointer, _ incY : Int32) -> Self 88 | 89 | static func blas_gemm(_ Order : CBLAS_ORDER, _ TransA : CBLAS_TRANSPOSE, _ TransB : CBLAS_TRANSPOSE, 90 | _ M : Int32, _ N : Int32, _ K : Int32, 91 | _ alpha : Self, _ A : UnsafePointer, _ lda : Int32, _ B : UnsafePointer, _ ldb : Int32, 92 | _ beta : Self, _ C : UnsafeMutablePointer, _ ldc : Int32) 93 | 94 | static func blas_gemv(_ Order : CBLAS_ORDER, _ TransA : CBLAS_TRANSPOSE, _ M : Int32, _ N : Int32, 95 | _ alpha : Self, _ A : UnsafePointer, _ lda : Int32, 96 | _ X : UnsafePointer, _ incX : Int32, 97 | _ beta : Self, _ Y : UnsafeMutablePointer, _ incY : Int32) 98 | 99 | static func blas_ger(_ Order : CBLAS_ORDER, _ M : Int32, _ N : Int32, 100 | _ alpha : Self, _ X : UnsafePointer, _ incX : Int32, 101 | _ Y : UnsafePointer, _ incY : Int32, 102 | _ A : UnsafeMutablePointer, _ lda : Int32) 103 | 104 | static func blas_gerAdjoint(_ Order : CBLAS_ORDER, _ M : Int32, _ N : Int32, 105 | _ alpha : Self, _ X : UnsafePointer, _ incX : Int32, 106 | _ Y : UnsafePointer, _ incY : Int32, 107 | _ A : UnsafeMutablePointer, _ lda : Int32) 108 | 109 | static func lapack_gesv(_ n : UnsafeMutablePointer, _ nrhs : UnsafeMutablePointer, 110 | _ a : UnsafeMutablePointer, _ lda : UnsafeMutablePointer, 111 | _ ipiv : UnsafeMutablePointer, 112 | _ b : UnsafeMutablePointer, _ ldb : UnsafeMutablePointer, 113 | _ info : UnsafeMutablePointer) -> Int32 114 | 115 | static func lapack_gels(_ trans : Transpose, 116 | _ m : UnsafeMutablePointer, _ n : UnsafeMutablePointer, _ nrhs : UnsafeMutablePointer, 117 | _ a : UnsafeMutablePointer, _ lda : UnsafeMutablePointer, 118 | _ b : UnsafeMutablePointer, _ ldb : UnsafeMutablePointer, 119 | _ work : UnsafeMutablePointer, _ lwork : UnsafeMutablePointer, 120 | _ info : UnsafeMutablePointer) -> Int32 121 | 122 | static func lapack_gesvd(_ jobu : UnsafeMutablePointer, _ jobvt : UnsafeMutablePointer, 123 | _ m : UnsafeMutablePointer, _ n : UnsafeMutablePointer, 124 | _ a : UnsafeMutablePointer, _ lda : UnsafeMutablePointer, 125 | _ s : UnsafeMutablePointer, 126 | _ u : UnsafeMutablePointer, _ ldu : UnsafeMutablePointer, 127 | _ vt : UnsafeMutablePointer, _ ldvt : UnsafeMutablePointer, 128 | _ work : UnsafeMutablePointer, _ lwork : UnsafeMutablePointer, 129 | _ info : UnsafeMutablePointer) -> Int32 130 | 131 | static func lapack_heev(_ jobz : UnsafeMutablePointer, _ uplo : UnsafeMutablePointer, _ n : UnsafeMutablePointer, 132 | _ a : UnsafeMutablePointer, _ lda : UnsafeMutablePointer, 133 | _ w : UnsafeMutablePointer, 134 | _ work : UnsafeMutablePointer, _ lwork : UnsafeMutablePointer, 135 | _ info : UnsafeMutablePointer) -> Int32 136 | 137 | static func lapack_gees(_ jobvs : UnsafeMutablePointer, _ n : UnsafeMutablePointer, 138 | _ a : UnsafeMutablePointer, _ lda : UnsafeMutablePointer, 139 | _ wr : UnsafeMutablePointer, 140 | _ wi : UnsafeMutablePointer, 141 | _ vs : UnsafeMutablePointer, _ ldvs : UnsafeMutablePointer, 142 | _ work : UnsafeMutablePointer, _ lwork : UnsafeMutablePointer, 143 | _ info : UnsafeMutablePointer) -> Int32 144 | 145 | static func vDSP_elementwise_absolute(_ v : [Self]) -> [Self.Magnitude] 146 | 147 | static func vDSP_elementwise_adjoint(_ v : [Self]) -> [Self] 148 | 149 | static func vDSP_elementwise_multiply(_ u : [Self], _ v : [Self]) -> [Self] 150 | 151 | static func vDSP_elementwise_divide(_ u : [Self], _ v : [Self]) -> [Self] 152 | 153 | } 154 | 155 | public extension LANumeric { 156 | 157 | /// Computes the sum of the manhattanLengths of all elements in `vector`. 158 | static func manhattanLength(_ vector : Vector) -> Self.Magnitude { 159 | return blas_asum(Int32(vector.count), vector, 1) 160 | } 161 | 162 | /// Computes the L2 norm of this `vector`. 163 | static func length(_ vector : Vector) -> Self.Magnitude { 164 | return blas_nrm2(Int32(vector.count), vector, 1) 165 | } 166 | 167 | /// Scales vector `A` element-wise by `alpha` and stores the result in `A`. 168 | static func scaleVector(_ alpha : Self, _ A : inout Vector) { 169 | let C = Int32(A.count) 170 | asMutablePointer(&A) { A in 171 | blas_scal(C, alpha, A, 1) 172 | } 173 | } 174 | 175 | /// Scales vector `A` element-wise by `alpha`, scales matrix `B` element-wise by `beta`, and and stores the sum of the two scaled matrices in `B`. 176 | static func scaleAndAddVectors(_ alpha : Self, _ A : Vector, _ beta : Self, _ B : inout Vector) { 177 | precondition(A.count == B.count) 178 | asMutablePointer(&B) { B in 179 | blas_axpby(Int32(A.count), alpha, A, 1, beta, B, 1) 180 | } 181 | } 182 | 183 | /// Returns the index of the element with the largest manhattan length (-1 if the vector is empty). 184 | static func indexOfManhattanLongestElem(_ vector: Vector) -> Int { 185 | guard !vector.isEmpty else { return -1 } 186 | return Int(blas_iamax(Int32(vector.count), vector, 1)) 187 | } 188 | 189 | /// Returns the index of the element with the largest magnitude (-1 if the vector is empty). 190 | static func indexOfLargestElem(_ vector: Vector) -> Int { 191 | guard !vector.isEmpty else { return -1 } 192 | return Int(blas_iamax_inf(Int32(vector.count), vector, 1)) 193 | } 194 | 195 | /// Returns the dot product of `A` and `B`. 196 | static func dotProduct(_ A: Vector, _ B: Vector) -> Self { 197 | precondition(A.count == B.count) 198 | return blas_dot(Int32(A.count), A, 1, B, 1) 199 | } 200 | 201 | /// Returns the dot product of `A′` and `B`. 202 | static func adjointDotProduct(_ A: Vector, _ B: Vector) -> Self { 203 | precondition(A.count == B.count) 204 | return blas_adjointDot(Int32(A.count), A, 1, B, 1) 205 | } 206 | 207 | /// Scales the product of `A` and `B` by `alpha` and adds it to the result of scaling `C` by `beta`. Optionally `A` and / or `B` can be transposed/adjoint prior to that. 208 | static func matrixProduct(_ alpha : Self, _ transposeA : Transpose, _ A : Matrix, _ transposeB : Transpose, _ B : Matrix, _ beta : Self, _ C : inout Matrix) { 209 | let M = Int32(transposeA != .none ? A.columns : A.rows) 210 | let N = Int32(transposeB != .none ? B.rows : B.columns) 211 | let KA = Int32(transposeA != .none ? A.rows : A.columns) 212 | let KB = Int32(transposeB != .none ? B.columns : B.rows) 213 | precondition(KA == KB) 214 | precondition(M == C.rows) 215 | precondition(N == C.columns) 216 | guard M > 0 && N > 0 && KA > 0 else { 217 | scaleVector(beta, &C.elements) 218 | return 219 | } 220 | asMutablePointer(&C.elements) { C in 221 | let ta = transposeA.cblas 222 | let tb = transposeB.cblas 223 | blas_gemm(CblasColMajor, ta, tb, M, N, KA, alpha, A.elements, Int32(A.rows), B.elements, Int32(B.rows), beta, C, M) 224 | } 225 | } 226 | 227 | /// Scales the product of `A` and `X` by `alpha` and adds it to the result of scaling `Y` by `beta`. Optionally `A` can be transposed/adjoint prior to that. 228 | static func matrixVectorProduct(_ alpha : Self, _ transposeA : Transpose, _ A : Matrix, _ X : Vector, _ beta : Self, _ Y : inout Vector) { 229 | let M = Int32(A.rows) 230 | let N = Int32(A.columns) 231 | precondition(transposeA != .none ? (N == Y.count) : (N == X.count)) 232 | precondition(transposeA != .none ? (M == X.count) : (M == Y.count)) 233 | guard M > 0 && N > 0 else { 234 | scaleVector(beta, &Y) 235 | return 236 | } 237 | asMutablePointer(&Y) { Y in 238 | let ta = transposeA.cblas 239 | blas_gemv(CblasColMajor, ta, M, N, alpha, A.elements, M, X, 1, beta, Y, 1) 240 | } 241 | } 242 | 243 | /// Scales the product of `X` and the transpose of `Y` by `alpha` and adds it to `A`. 244 | static func vectorVectorProduct(_ alpha : Self, _ X : Vector, _ Y : Vector, _ A : inout Matrix) { 245 | let M = Int32(A.rows) 246 | let N = Int32(A.columns) 247 | precondition(M == X.count) 248 | precondition(N == Y.count) 249 | guard M > 0 && N > 0 else { return } 250 | asMutablePointer(&A.elements) { A in 251 | blas_ger(CblasColMajor, M, N, alpha, X, 1, Y, 1, A, M) 252 | } 253 | } 254 | 255 | /// Scales the product of `X` and the adjoint of `Y` by `alpha` and adds it to `A`. 256 | static func vectorAdjointVectorProduct(_ alpha : Self, _ X : Vector, _ Y : Vector, _ A : inout Matrix) { 257 | let M = Int32(A.rows) 258 | let N = Int32(A.columns) 259 | precondition(M == X.count) 260 | precondition(N == Y.count) 261 | guard M > 0 && N > 0 else { return } 262 | asMutablePointer(&A.elements) { A in 263 | blas_gerAdjoint(CblasColMajor, M, N, alpha, X, 1, Y, 1, A, M) 264 | } 265 | } 266 | 267 | /// Solves the system of linear equations `A * X = B` and stores the result `X` in `B`. 268 | /// - returns: `true` if the operation completed successfully, `false` otherwise. 269 | static func solveLinearEquations(_ A : Matrix, _ B : inout Matrix) -> Bool { 270 | var n = IntLA(A.rows) 271 | precondition(A.columns == n && B.rows == n) 272 | var lda = n 273 | var ldb = n 274 | var info : IntLA = 0 275 | var nrhs = IntLA(B.columns) 276 | var ipiv = [IntLA](repeating: 0, count: Int(n)) 277 | var A = A.elements 278 | asMutablePointer(&A) { A in 279 | asMutablePointer(&B.elements) { B in 280 | asMutablePointer(&ipiv) { ipiv in 281 | let _ = lapack_gesv(&n, &nrhs, A, &lda, ipiv, B, &ldb, &info) 282 | } 283 | } 284 | } 285 | return info == 0 286 | } 287 | 288 | /// Finds the minimum least squares solutions `x` of minimizing `(b - A * x).length` or `(b - A′ * x).length` and returns the result. 289 | /// Each column `x` in the result corresponds to the solution for the corresponding column `b` in `B`. 290 | static func solveLinearLeastSquares(_ A : Matrix, _ transposeA : Transpose, _ B : Matrix) -> Matrix? { 291 | var m : IntLA = IntLA(A.rows) 292 | var n : IntLA = IntLA(A.columns) 293 | let X = transposeA != .none ? A.rows : A.columns 294 | precondition(transposeA != .none ? B.rows == n : B.rows == m) 295 | var A = A 296 | A.extend(rows: 1) 297 | var B = B 298 | B.extend(rows: Int(max(1, max(n, m)))) 299 | var nrhs : IntLA = IntLA(B.columns) 300 | var lda : IntLA = IntLA(A.rows) 301 | var ldb : IntLA = IntLA(B.rows) 302 | var lwork : IntLA = -1 303 | var info : IntLA = 0 304 | asMutablePointer(&A.elements) { A in 305 | asMutablePointer(&B.elements) { B in 306 | var workCount : Self = 0 307 | let _ = lapack_gels(transposeA, &m, &n, &nrhs, A, &lda, B, &ldb, &workCount, &lwork, &info) 308 | guard info == 0 else { return } 309 | var work = [Self](repeating: 0, count: workCount.toInt) 310 | lwork = IntLA(work.count) 311 | let _ = lapack_gels(transposeA, &m, &n, &nrhs, A, &lda, B, &ldb, &work, &lwork, &info) 312 | } 313 | } 314 | guard info == 0 else { return nil } 315 | return B[0 ..< X, 0 ..< B.columns] 316 | } 317 | 318 | /// Computes the singular value decomposition of a matrix`A` with `m` rows and `n` columns such that `A ≈ left * D * right`. 319 | /// Here `D == Matrix(rows: m, columns: n, diagonal: singularValues)` and `singularValues` has `min(m, n)` elements. 320 | /// The result matrix `left` has `m` rows, and depending on its job parameter either `m` (`all`), `min(m, n)` (`singular`) or `0` (`none`) columns. 321 | /// The result matrix `right` has `n` columns, and depending on its job parameter either `n` (`all`), `min(m, n)` (`singular`) or `0` (`none`) rows. 322 | static func singularValueDecomposition(_ A : Matrix, left : SVDJob, right : SVDJob) -> (singularValues : Vector, left : Matrix, right : Matrix)? { 323 | var m = IntLA(A.rows) 324 | var n = IntLA(A.columns) 325 | let k = min(m, n) 326 | let leftColumns : IntLA 327 | switch left { 328 | case .all: leftColumns = m 329 | case .singular: leftColumns = k 330 | case .none: leftColumns = 0 331 | } 332 | let rightRows : IntLA 333 | switch right { 334 | case .all: rightRows = n 335 | case .singular: rightRows = k 336 | case .none: rightRows = 0 337 | } 338 | guard k > 0 else { 339 | let U : Matrix = .eye(Int(m), Int(leftColumns)) 340 | let VT : Matrix = .eye(Int(rightRows), Int(n)) 341 | return (singularValues: [], left: U, right: VT) 342 | } 343 | var A = A 344 | var lda = m 345 | var S = Vector(repeating: 0, count: Int(k)) 346 | var ldu = m 347 | var U = Matrix(rows: Int(ldu), columns: Int(leftColumns)) 348 | var ldvt = max(1, rightRows) 349 | var VT = Matrix(rows: Int(ldvt), columns: Int(n)) 350 | var jobleft = left.lapackJob 351 | var jobright = right.lapackJob 352 | var info : IntLA = 0 353 | var lwork : IntLA = -1 354 | asMutablePointer(&A.elements) { A in 355 | asMutablePointer(&S) { S in 356 | asMutablePointer(&U.elements) { U in 357 | asMutablePointer(&VT.elements) { VT in 358 | var workCount : Self = 0 359 | let _ = lapack_gesvd(&jobleft, &jobright, &m, &n, A, &lda, S, U, &ldu, VT, &ldvt, &workCount, &lwork, &info) 360 | guard info == 0 else { return } 361 | var work = [Self](repeating: 0, count: workCount.toInt) 362 | lwork = IntLA(work.count) 363 | let _ = lapack_gesvd(&jobleft, &jobright, &m, &n, A, &lda, S, U, &ldu, VT, &ldvt, &work, &lwork, &info) 364 | } 365 | } 366 | } 367 | } 368 | if info == 0 { 369 | if rightRows == 0 { 370 | VT = Matrix(rows: 0, columns: VT.columns) 371 | } 372 | return (singularValues: S, left: U, right: VT) 373 | } else { 374 | return nil 375 | } 376 | } 377 | 378 | /// Computes the eigen decomposition of `A`. Here `A == A′` is assumed, and thus only the upper triangle part of `A` is used. 379 | /// The eigen vectors of `A` are stored in `A` if successful, otherwise the resulting content of `A` is undefined. 380 | /// - returns: `nil` if the decomposition failed, otherwise the eigenvalues of `A` 381 | static func eigenDecomposition(_ A : inout Matrix) -> Vector? { 382 | var n = IntLA(A.rows) 383 | precondition(n == A.columns) 384 | guard n > 0 else { return [] } 385 | var jobz : Int8 = 0x56 /* "V" */ 386 | var uplo : Int8 = 0x55 /* "U" */ 387 | var lda = n 388 | var w : [Magnitude] = Array(repeating: 0, count: Int(n)) 389 | var info : IntLA = 0 390 | var lwork : IntLA = -1 391 | asMutablePointer(&A.elements) { a in 392 | asMutablePointer(&w) { w in 393 | var workCount : Self = 0 394 | let _ = lapack_heev(&jobz, &uplo, &n, a, &lda, w, &workCount, &lwork, &info) 395 | guard info == 0 else { return } 396 | var work = [Self](repeating: 0, count: workCount.toInt) 397 | lwork = IntLA(work.count) 398 | let _ = lapack_heev(&jobz, &uplo, &n, a, &lda, w, &work, &lwork, &info) 399 | } 400 | } 401 | if info == 0 { 402 | return w 403 | } else { 404 | return nil 405 | } 406 | } 407 | 408 | /// Computes schur decomposition of `A`. 409 | static func schurDecomposition(_ A : inout Matrix) -> (eigenValues : Vector>, schurVectors : Matrix)? where R == Self.Magnitude { 410 | var n = IntLA(A.rows) 411 | precondition(n == A.columns) 412 | guard n > 0 else { return (eigenValues : [], schurVectors : Matrix()) } 413 | var jobvs : Int8 = 0x56 /* "V" */ 414 | var lda = n 415 | var w : [Complex] = Array(repeating: 0, count: Int(n)) 416 | var wr : [Self.Magnitude] = Array(repeating: 0, count: Int(n)) 417 | var wi : [Self.Magnitude] = Array(repeating: 0, count: Int(n)) 418 | var info : IntLA = 0 419 | var lwork : IntLA = -1 420 | var vs = Matrix(rows: Int(n), columns: Int(n)) 421 | var ldvs = n 422 | asMutablePointer(&A.elements) { a in 423 | asMutablePointer(&w) { w in 424 | asMutablePointer(&vs.elements) { vs in 425 | var workCount : Self = 0 426 | let _ = lapack_gees(&jobvs, &n, a, &lda, &wr, &wi, vs, &ldvs, &workCount, &lwork, &info) 427 | guard info == 0 else { return } 428 | var work = [Self](repeating: 0, count: workCount.toInt) 429 | lwork = IntLA(work.count) 430 | let _ = lapack_gees(&jobvs, &n, a, &lda, &wr, &wi, vs, &ldvs, &work, &lwork, &info) 431 | } 432 | } 433 | } 434 | if info == 0 { 435 | for i in 0 ..< A.rows { 436 | w[i] = Complex(wr[i], wi[i]) 437 | } 438 | return (eigenValues: w, schurVectors : vs) 439 | } else { 440 | return nil 441 | } 442 | } 443 | 444 | } 445 | 446 | infix operator ′* : MultiplicationPrecedence 447 | infix operator *′ : MultiplicationPrecedence 448 | infix operator ′*′ : MultiplicationPrecedence 449 | infix operator ∖ : MultiplicationPrecedence // unicode character "set minus": U+2216 450 | infix operator ′∖ : MultiplicationPrecedence 451 | 452 | infix operator .* : MultiplicationPrecedence 453 | infix operator ./ : MultiplicationPrecedence 454 | infix operator .- : AdditionPrecedence 455 | infix operator .+ : AdditionPrecedence 456 | 457 | public extension Matrix where Element : Numeric { 458 | 459 | static func eye(_ m : Int) -> Matrix { 460 | return Matrix(diagonal : [Element](repeating: 1, count: m)) 461 | } 462 | 463 | static func eye(_ m : Int, _ n : Int) -> Matrix { 464 | return Matrix(rows: m, columns: n, diagonal : [Element](repeating: 1, count: min(n, m))) 465 | } 466 | 467 | } 468 | 469 | public extension Matrix where Element : LANumeric { 470 | 471 | var manhattanNorm : Element.Magnitude { return Element.manhattanLength(elements) } 472 | 473 | var norm : Element.Magnitude { return Element.length(elements) } 474 | 475 | var manhattanLongest : Element { 476 | let index = Element.indexOfManhattanLongestElem(elements) 477 | if index >= 0 { 478 | return elements[index] 479 | } else { 480 | return 0 481 | } 482 | } 483 | 484 | var largest : Element { 485 | let index = Element.indexOfLargestElem(elements) 486 | if index >= 0 { 487 | return elements[index] 488 | } else { 489 | return 0 490 | } 491 | } 492 | 493 | var infNormManhattan : Element.Magnitude { 494 | return manhattanLongest.manhattanLength 495 | } 496 | 497 | var infNorm : Element.Magnitude { 498 | return largest.magnitude 499 | } 500 | 501 | static func + (left : Matrix, right : Matrix) -> Matrix { 502 | var result = left 503 | result += right 504 | return result 505 | } 506 | 507 | static func - (left : Matrix, right : Matrix) -> Matrix { 508 | var result = left 509 | result -= right 510 | return result 511 | } 512 | 513 | static prefix func -(matrix : Matrix) -> Matrix { 514 | return -1 * matrix 515 | } 516 | 517 | static func += (left : inout Matrix, right : Matrix) { 518 | left.accumulate(1, 1, right) 519 | } 520 | 521 | static func -= (left : inout Matrix, right : Matrix) { 522 | left.accumulate(1, -1, right) 523 | } 524 | 525 | mutating func accumulate(_ alpha : Element, _ beta : Element, _ other : Matrix) { 526 | precondition(hasSameDimensions(other)) 527 | Element.scaleAndAddVectors(beta, other.elements, alpha, &self.elements) 528 | } 529 | 530 | static func * (left : Matrix, right : Matrix) -> Matrix { 531 | var C = Matrix(rows: left.rows, columns: right.columns) 532 | Element.matrixProduct(1, .none, left, .none, right, 0, &C) 533 | return C 534 | } 535 | 536 | static func ′* (left : Matrix, right : Matrix) -> Matrix { 537 | var C = Matrix(rows: left.columns, columns: right.columns) 538 | Element.matrixProduct(1, .adjoint, left, .none, right, 0, &C) 539 | return C 540 | } 541 | 542 | static func *′ (left : Matrix, right : Matrix) -> Matrix { 543 | var C = Matrix(rows: left.rows, columns: right.rows) 544 | Element.matrixProduct(1, .none, left, .adjoint, right, 0, &C) 545 | return C 546 | } 547 | 548 | static func ′*′ (left : Matrix, right : Matrix) -> Matrix { 549 | var C = Matrix(rows: left.columns, columns: right.rows) 550 | Element.matrixProduct(1, .adjoint, left, .adjoint, right, 0, &C) 551 | return C 552 | } 553 | 554 | static func * (left : Matrix, right : Vector) -> Vector { 555 | var Y = [Element](repeating: Element.zero, count: left.rows) 556 | Element.matrixVectorProduct(1, .none, left, right, 0, &Y) 557 | return Y 558 | } 559 | 560 | static func ′* (left : Matrix, right : Vector) -> Vector { 561 | var Y = [Element](repeating: Element.zero, count: left.columns) 562 | Element.matrixVectorProduct(1, .adjoint, left, right, 0, &Y) 563 | return Y 564 | } 565 | 566 | static func *= (left : inout Matrix, right : Element) { 567 | Element.scaleVector(right, &left.elements) 568 | } 569 | 570 | static func * (left : Element, right : Matrix) -> Matrix { 571 | var A = right 572 | A *= left 573 | return A 574 | } 575 | 576 | static func .+(left : Matrix, right : Matrix) -> Matrix { 577 | return left + right 578 | } 579 | 580 | static func .-(left : Matrix, right : Matrix) -> Matrix { 581 | return left - right 582 | } 583 | 584 | static func .*(left : Matrix, right : Matrix) -> Matrix { 585 | precondition(left.hasSameDimensions(right)) 586 | let elems = Element.vDSP_elementwise_multiply(left.elements, right.elements) 587 | return Matrix(rows: left.rows, columns: left.columns, elements: elems) 588 | } 589 | 590 | static func ./(left : Matrix, right : Matrix) -> Matrix { 591 | precondition(left.hasSameDimensions(right)) 592 | let elems = Element.vDSP_elementwise_divide(left.elements, right.elements) 593 | return Matrix(rows: left.rows, columns: left.columns, elements: elems) 594 | } 595 | 596 | func solve(_ rhs : Matrix) -> Matrix? { 597 | var B = rhs 598 | if Element.solveLinearEquations(self, &B) { 599 | return B 600 | } else { 601 | return nil 602 | } 603 | } 604 | 605 | func solve(_ rhs : Vector) -> Vector? { 606 | return solve(Matrix(rhs))?.vector 607 | } 608 | 609 | func solveLeastSquares(transpose : Transpose = .none, _ rhs : Matrix) -> Matrix? { 610 | return Element.solveLinearLeastSquares(self, transpose, rhs) 611 | } 612 | 613 | func solveLeastSquares(transpose : Transpose = .none, _ rhs : Vector) -> Vector? { 614 | return Element.solveLinearLeastSquares(self, transpose, Matrix(rhs))?.vector 615 | } 616 | 617 | func svd(left : SVDJob = .all, right : SVDJob = .all) -> (singularValues : Vector, left : Matrix, right : Matrix)? { 618 | return Element.singularValueDecomposition(self, left: left, right: right) 619 | } 620 | 621 | func eigen() -> (eigenValues : Vector, eigenVectors : Matrix)? { 622 | var A = self 623 | guard let eigenValues = Element.eigenDecomposition(&A) else { return nil } 624 | return (eigenValues: eigenValues, eigenVectors: A) 625 | } 626 | 627 | func schur() -> (eigenValues : Vector>, schurForm : Matrix, schurVectors : Matrix)? where R == Element.Magnitude { 628 | var A = self 629 | guard let result = Element.schurDecomposition(&A) else { return nil } 630 | return (eigenValues: result.eigenValues, schurForm: A, schurVectors: result.schurVectors) 631 | } 632 | 633 | static func ∖ (lhs : Matrix, rhs : Matrix) -> Matrix { 634 | return lhs.solveLeastSquares(rhs)! 635 | } 636 | 637 | static func ∖ (lhs : Matrix, rhs : Vector) -> Vector { 638 | return lhs.solveLeastSquares(rhs)! 639 | } 640 | 641 | static func ′∖ (lhs : Matrix, rhs : Matrix) -> Matrix { 642 | return lhs.solveLeastSquares(transpose: .adjoint, rhs)! 643 | } 644 | 645 | static func ′∖ (lhs : Matrix, rhs : Vector) -> Vector { 646 | return lhs.solveLeastSquares(transpose: .adjoint, rhs)! 647 | } 648 | 649 | var inverse : Matrix? { 650 | guard rows == columns else { return nil } 651 | return self.solveLeastSquares(.eye(rows)) 652 | } 653 | 654 | } 655 | 656 | public func * (left : Vector, right : Vector) -> Element { 657 | return Element.dotProduct(left, right) 658 | } 659 | 660 | public func ′* (left : Vector, right : Vector) -> Element { 661 | return Element.adjointDotProduct(left, right) 662 | } 663 | 664 | public func *′ (left : Vector, right : Vector) -> Matrix { 665 | var A = Matrix(rows: left.count, columns: right.count) 666 | Element.vectorAdjointVectorProduct(1, left, right, &A) 667 | return A 668 | } 669 | 670 | public postfix func ′(vector : Vector) -> Matrix { 671 | return Matrix(row: Element.vDSP_elementwise_adjoint(vector)) 672 | } 673 | 674 | public func .+(left : Vector, right : Vector) -> Vector { 675 | var B = right 676 | Element.scaleAndAddVectors(1, left, 1, &B) 677 | return B 678 | } 679 | 680 | public func .-(left : Vector, right : Vector) -> Vector { 681 | var B = right 682 | Element.scaleAndAddVectors(1, left, -1, &B) 683 | return B 684 | } 685 | 686 | public func .*(left : Vector, right : Vector) -> Vector { 687 | return Element.vDSP_elementwise_multiply(left, right) 688 | } 689 | 690 | public func ./(left : Vector, right : Vector) -> Vector { 691 | return Element.vDSP_elementwise_divide(left, right) 692 | } 693 | 694 | 695 | 696 | 697 | -------------------------------------------------------------------------------- /Sources/LANumerics/Matrix.swift: -------------------------------------------------------------------------------- 1 | public protocol MatrixElement : Hashable { 2 | 3 | static var zero : Self { get } 4 | 5 | var adjoint : Self { get } 6 | 7 | } 8 | 9 | public typealias Vector = [Element] 10 | 11 | public struct Matrix : MatrixElement { 12 | 13 | /// We keep elements in [column-major order](https://en.wikipedia.org/wiki/Row-_and_column-major_order). 14 | var elements : Vector 15 | 16 | var _rows : Int 17 | 18 | var _columns : Int 19 | 20 | /// The number of rows of the matrix. 21 | public var rows : Int { 22 | return _rows 23 | } 24 | 25 | /// The number of columns of the matrix. 26 | public var columns : Int { 27 | return _columns 28 | } 29 | 30 | public init() { 31 | self._rows = 0 32 | self._columns = 0 33 | self.elements = [] 34 | } 35 | 36 | public init(repeating : Element = Element.zero, rows : Int, columns : Int) { 37 | precondition(rows >= 0 && columns >= 0) 38 | self._rows = rows 39 | self._columns = columns 40 | elements = [Element](repeating: repeating, count: rows * columns) 41 | } 42 | 43 | public init(rows : Int, columns : Int, elements : (_ row : Int, _ column : Int) -> Element) { 44 | precondition(rows >= 0 && columns >= 0) 45 | self._rows = rows 46 | self._columns = columns 47 | self.elements = [Element](repeating: Element.zero, count: rows * columns) 48 | var index = 0 49 | for c in 0 ..< columns { 50 | for r in 0 ..< rows { 51 | self.elements[index] = elements(r, c) 52 | index += 1 53 | } 54 | } 55 | } 56 | 57 | public init(rows : Int, columns : Int, elements : Vector) { 58 | precondition(rows >= 0 && columns >= 0 && rows * columns == elements.count) 59 | self._rows = rows 60 | self._columns = columns 61 | self.elements = elements 62 | } 63 | 64 | public init(row : Vector) { 65 | self._rows = 1 66 | self._columns = row.count 67 | self.elements = row 68 | } 69 | 70 | public init(_ column : Vector) { 71 | self._columns = 1 72 | self._rows = column.count 73 | self.elements = column 74 | } 75 | 76 | public init(_ singleton : Element) { 77 | self._columns = 1 78 | self._rows = 1 79 | self.elements = [singleton] 80 | } 81 | 82 | public init(diagonal : Vector) { 83 | let m = diagonal.count 84 | self.init(rows: m, columns: m, diagonal: diagonal) 85 | } 86 | 87 | public init(rows : Int, columns : Int, diagonal : Vector) { 88 | let m = diagonal.count 89 | precondition(m <= min(rows, columns)) 90 | self._rows = rows 91 | self._columns = columns 92 | self.elements = [Element](repeating: Element.zero, count: rows * columns) 93 | for i in 0 ..< m { 94 | self[i, i] = diagonal[i] 95 | } 96 | } 97 | 98 | public func hasDimensions(_ rows : Int, _ columns : Int) -> Bool { 99 | return rows == self._rows && columns == self._columns 100 | } 101 | 102 | public static func zeros(_ rows : Int, _ columns : Int) -> Matrix { 103 | return Matrix(rows: rows, columns: columns) 104 | } 105 | 106 | private func indexIsValid(row : Int, column : Int) -> Bool { 107 | return row >= 0 && column >= 0 && row < _rows && column < _columns 108 | } 109 | 110 | func hasSameDimensions(_ other : Matrix) -> Bool { 111 | return _rows == other._rows && _columns == other._columns 112 | } 113 | 114 | public var isRowVector : Bool { return _rows == 1 } 115 | 116 | public var isColumnVector : Bool { return _columns == 1 } 117 | 118 | public var isVector : Bool { return _rows == 1 || _columns == 1 } 119 | 120 | /// Returns the number of elements in this matrix. 121 | public var count : Int { return _rows * _columns } 122 | 123 | /// Returns the matrix as vector. This also succeeds if the matrix is not an actual vector, the elements are then in column-major order. 124 | public var vector : Vector { return elements } 125 | 126 | public subscript(row : Int, column : Int) -> Element { 127 | get { 128 | precondition(indexIsValid(row: row, column: column)) 129 | return elements[column * _rows + row] 130 | } 131 | set { 132 | precondition(indexIsValid(row: row, column: column)) 133 | elements[column * _rows + row] = newValue 134 | } 135 | } 136 | 137 | /// Gets / sets the element at `index` when viewing the matrix as a vector (with elements in column-major order). 138 | public subscript(index : Int) -> Element { 139 | get { 140 | return elements[index] 141 | } 142 | set { 143 | elements[index] = newValue 144 | } 145 | } 146 | 147 | public static var zero: Matrix { 148 | return Matrix() 149 | } 150 | 151 | } 152 | 153 | -------------------------------------------------------------------------------- /Sources/LANumerics/SIMD.swift: -------------------------------------------------------------------------------- 1 | import simd 2 | 3 | public extension Matrix where Element : SIMDScalar { 4 | 5 | init(_ simd : SIMD2) { 6 | self.init([simd.x, simd.y]) 7 | } 8 | 9 | init(_ simd : SIMD3) { 10 | self.init([simd.x, simd.y, simd.z]) 11 | } 12 | 13 | init(_ simd : SIMD4) { 14 | self.init([simd.x, simd.y, simd.z, simd.w]) 15 | } 16 | 17 | init(_ simd : SIMD8) { 18 | self.init((0 ..< 8).map { i in simd[i] }) 19 | } 20 | 21 | init(_ simd : SIMD16) { 22 | self.init((0 ..< 16).map { i in simd[i] }) 23 | } 24 | 25 | init(_ simd : SIMD32) { 26 | self.init((0 ..< 32).map { i in simd[i] }) 27 | } 28 | 29 | init(_ simd : SIMD64) { 30 | self.init((0 ..< 64).map { i in simd[i] }) 31 | } 32 | 33 | init(row simd : SIMD2) { 34 | self.init(row: [simd.x, simd.y]) 35 | } 36 | 37 | init(row simd : SIMD3) { 38 | self.init(row: [simd.x, simd.y, simd.z]) 39 | } 40 | 41 | init(row simd : SIMD4) { 42 | self.init(row: [simd.x, simd.y, simd.z, simd.w]) 43 | } 44 | 45 | init(row simd : SIMD8) { 46 | self.init(row: (0 ..< 8).map { i in simd[i] }) 47 | } 48 | 49 | init(row simd : SIMD16) { 50 | self.init(row: (0 ..< 16).map { i in simd[i] }) 51 | } 52 | 53 | init(row simd : SIMD32) { 54 | self.init(row: (0 ..< 32).map { i in simd[i] }) 55 | } 56 | 57 | init(row simd : SIMD64) { 58 | self.init(row: (0 ..< 64).map { i in simd[i] }) 59 | } 60 | 61 | var simd2 : SIMD2 { 62 | return SIMD2(elements) 63 | } 64 | 65 | var simd3 : SIMD3 { 66 | return SIMD3(elements) 67 | } 68 | 69 | var simd4 : SIMD4 { 70 | return SIMD4(elements) 71 | } 72 | 73 | var simd8 : SIMD8 { 74 | return SIMD8(elements) 75 | } 76 | 77 | var simd16 : SIMD16 { 78 | return SIMD16(elements) 79 | } 80 | 81 | var simd32 : SIMD32 { 82 | return SIMD32(elements) 83 | } 84 | 85 | var simd64 : SIMD64 { 86 | return SIMD64(elements) 87 | } 88 | 89 | } 90 | 91 | public extension Matrix where Element == Float { 92 | 93 | init(_ simd : simd_float2x2) { 94 | let (col0, col1) = simd.columns 95 | self.init(rows: 2, columns: 2, elements: [col0[0], col0[1], col1[0], col1[1]]) 96 | } 97 | 98 | init(_ simd : simd_float2x3) { 99 | let (col0, col1) = simd.columns 100 | self.init(rows: 3, columns: 2, elements: [col0[0], col0[1], col0[2], col1[0], col1[1], col1[2]]) 101 | } 102 | 103 | init(_ simd : simd_float2x4) { 104 | let (col0, col1) = simd.columns 105 | self.init(rows: 4, columns: 2, elements: [col0[0], col0[1], col0[2], col0[3], col1[0], col1[1], col1[2], col1[3]]) 106 | } 107 | 108 | init(_ simd : simd_float3x2) { 109 | let (col0, col1, col2) = simd.columns 110 | self.init(rows: 2, columns: 3, elements: [col0[0], col0[1], col1[0], col1[1], col2[0], col2[1]]) 111 | } 112 | 113 | init(_ simd : simd_float3x3) { 114 | let (col0, col1, col2) = simd.columns 115 | self.init(rows: 3, columns: 3, elements: [col0[0], col0[1], col0[2], col1[0], col1[1], col1[2], col2[0], col2[1], col2[2]]) 116 | } 117 | 118 | init(_ simd : simd_float3x4) { 119 | let (col0, col1, col2) = simd.columns 120 | self.init(rows: 4, columns: 3, elements: [col0[0], col0[1], col0[2], col0[3], col1[0], col1[1], col1[2], col1[3], col2[0], col2[1], col2[2], col2[3]]) 121 | } 122 | 123 | init(_ simd : simd_float4x2) { 124 | let (col0, col1, col2, col3) = simd.columns 125 | self.init(rows: 2, columns: 4, elements: [col0[0], col0[1], col1[0], col1[1], col2[0], col2[1], col3[0], col3[1]]) 126 | } 127 | 128 | init(_ simd : simd_float4x3) { 129 | let (col0, col1, col2, col3) = simd.columns 130 | self.init(rows: 3, columns: 4, elements: [col0[0], col0[1], col0[2], col1[0], col1[1], col1[2], col2[0], col2[1], col2[2], col3[0], col3[1], col3[2]]) 131 | } 132 | 133 | init(_ simd : simd_float4x4) { 134 | let (col0, col1, col2, col3) = simd.columns 135 | self.init(rows: 4, columns: 4, elements: [col0[0], col0[1], col0[2], col0[3], col1[0], col1[1], col1[2], col1[3], col2[0], col2[1], col2[2], col2[3], col3[0], col3[1], col3[2], col3[3]]) 136 | } 137 | 138 | var simd2x2 : simd_float2x2 { 139 | precondition(hasDimensions(2, 2)) 140 | return simd_float2x2(columns: (column(0).simd2, column(1).simd2)) 141 | } 142 | 143 | var simd2x3 : simd_float2x3 { 144 | precondition(hasDimensions(3, 2)) 145 | return simd_float2x3(columns: (column(0).simd3, column(1).simd3)) 146 | } 147 | 148 | var simd2x4 : simd_float2x4 { 149 | precondition(hasDimensions(4, 2)) 150 | return simd_float2x4(columns: (column(0).simd4, column(1).simd4)) 151 | } 152 | 153 | var simd3x2 : simd_float3x2 { 154 | precondition(hasDimensions(2, 3)) 155 | return simd_float3x2(columns: (column(0).simd2, column(1).simd2, column(2).simd2)) 156 | } 157 | 158 | var simd3x3 : simd_float3x3 { 159 | precondition(hasDimensions(3, 3)) 160 | return simd_float3x3(columns: (column(0).simd3, column(1).simd3, column(2).simd3)) 161 | } 162 | 163 | var simd3x4 : simd_float3x4 { 164 | precondition(hasDimensions(4, 3)) 165 | return simd_float3x4(columns: (column(0).simd4, column(1).simd4, column(2).simd4)) 166 | } 167 | 168 | var simd4x2 : simd_float4x2 { 169 | precondition(hasDimensions(2, 4)) 170 | return simd_float4x2(columns: (column(0).simd2, column(1).simd2, column(2).simd2, column(3).simd2)) 171 | } 172 | 173 | var simd4x3 : simd_float4x3 { 174 | precondition(hasDimensions(3, 4)) 175 | return simd_float4x3(columns: (column(0).simd3, column(1).simd3, column(2).simd3, column(3).simd3)) 176 | } 177 | 178 | var simd4x4 : simd_float4x4 { 179 | precondition(hasDimensions(4, 4)) 180 | return simd_float4x4(columns: (column(0).simd4, column(1).simd4, column(2).simd4, column(3).simd4)) 181 | } 182 | 183 | } 184 | 185 | public extension Matrix where Element == Double { 186 | 187 | init(_ simd : simd_double2x2) { 188 | let (col0, col1) = simd.columns 189 | self.init(rows: 2, columns: 2, elements: [col0[0], col0[1], col1[0], col1[1]]) 190 | } 191 | 192 | init(_ simd : simd_double2x3) { 193 | let (col0, col1) = simd.columns 194 | self.init(rows: 3, columns: 2, elements: [col0[0], col0[1], col0[2], col1[0], col1[1], col1[2]]) 195 | } 196 | 197 | init(_ simd : simd_double2x4) { 198 | let (col0, col1) = simd.columns 199 | self.init(rows: 4, columns: 2, elements: [col0[0], col0[1], col0[2], col0[3], col1[0], col1[1], col1[2], col1[3]]) 200 | } 201 | 202 | init(_ simd : simd_double3x2) { 203 | let (col0, col1, col2) = simd.columns 204 | self.init(rows: 2, columns: 3, elements: [col0[0], col0[1], col1[0], col1[1], col2[0], col2[1]]) 205 | } 206 | 207 | init(_ simd : simd_double3x3) { 208 | let (col0, col1, col2) = simd.columns 209 | self.init(rows: 3, columns: 3, elements: [col0[0], col0[1], col0[2], col1[0], col1[1], col1[2], col2[0], col2[1], col2[2]]) 210 | } 211 | 212 | init(_ simd : simd_double3x4) { 213 | let (col0, col1, col2) = simd.columns 214 | self.init(rows: 4, columns: 3, elements: [col0[0], col0[1], col0[2], col0[3], col1[0], col1[1], col1[2], col1[3], col2[0], col2[1], col2[2], col2[3]]) 215 | } 216 | 217 | init(_ simd : simd_double4x2) { 218 | let (col0, col1, col2, col3) = simd.columns 219 | self.init(rows: 2, columns: 4, elements: [col0[0], col0[1], col1[0], col1[1], col2[0], col2[1], col3[0], col3[1]]) 220 | } 221 | 222 | init(_ simd : simd_double4x3) { 223 | let (col0, col1, col2, col3) = simd.columns 224 | self.init(rows: 3, columns: 4, elements: [col0[0], col0[1], col0[2], col1[0], col1[1], col1[2], col2[0], col2[1], col2[2], col3[0], col3[1], col3[2]]) 225 | } 226 | 227 | init(_ simd : simd_double4x4) { 228 | let (col0, col1, col2, col3) = simd.columns 229 | self.init(rows: 4, columns: 4, elements: [col0[0], col0[1], col0[2], col0[3], col1[0], col1[1], col1[2], col1[3], col2[0], col2[1], col2[2], col2[3], col3[0], col3[1], col3[2], col3[3]]) 230 | } 231 | 232 | var simd2x2 : simd_double2x2 { 233 | precondition(hasDimensions(2, 2)) 234 | return simd_double2x2(columns: (column(0).simd2, column(1).simd2)) 235 | } 236 | 237 | var simd2x3 : simd_double2x3 { 238 | precondition(hasDimensions(3, 2)) 239 | return simd_double2x3(columns: (column(0).simd3, column(1).simd3)) 240 | } 241 | 242 | var simd2x4 : simd_double2x4 { 243 | precondition(hasDimensions(4, 2)) 244 | return simd_double2x4(columns: (column(0).simd4, column(1).simd4)) 245 | } 246 | 247 | var simd3x2 : simd_double3x2 { 248 | precondition(hasDimensions(2, 3)) 249 | return simd_double3x2(columns: (column(0).simd2, column(1).simd2, column(2).simd2)) 250 | } 251 | 252 | var simd3x3 : simd_double3x3 { 253 | precondition(hasDimensions(3, 3)) 254 | return simd_double3x3(columns: (column(0).simd3, column(1).simd3, column(2).simd3)) 255 | } 256 | 257 | var simd3x4 : simd_double3x4 { 258 | precondition(hasDimensions(4, 3)) 259 | return simd_double3x4(columns: (column(0).simd4, column(1).simd4, column(2).simd4)) 260 | } 261 | 262 | var simd4x2 : simd_double4x2 { 263 | precondition(hasDimensions(2, 4)) 264 | return simd_double4x2(columns: (column(0).simd2, column(1).simd2, column(2).simd2, column(3).simd2)) 265 | } 266 | 267 | var simd4x3 : simd_double4x3 { 268 | precondition(hasDimensions(3, 4)) 269 | return simd_double4x3(columns: (column(0).simd3, column(1).simd3, column(2).simd3, column(3).simd3)) 270 | } 271 | 272 | var simd4x4 : simd_double4x4 { 273 | precondition(hasDimensions(4, 4)) 274 | return simd_double4x4(columns: (column(0).simd4, column(1).simd4, column(2).simd4, column(3).simd4)) 275 | } 276 | 277 | } 278 | 279 | -------------------------------------------------------------------------------- /Sources/LANumerics/Shape.swift: -------------------------------------------------------------------------------- 1 | postfix operator ′ // unicode character "Prime": U+2032 2 | 3 | public postfix func ′(vector : Vector) -> Matrix { 4 | return Matrix(row: vector.map { x in x.adjoint }) 5 | } 6 | 7 | public postfix func ′(matrix : Matrix) -> Matrix { 8 | return matrix.adjoint 9 | } 10 | 11 | public typealias BlockMatrix = Matrix> 12 | 13 | public extension Matrix { 14 | 15 | internal mutating func transposeInPlace() { 16 | if _rows > 1 && _columns > 1 { 17 | var transposedElements = elements 18 | asPointer(elements) { elements in 19 | asMutablePointer(&transposedElements) { transposedElements in 20 | for r in 0 ..< _rows { 21 | for c in 0 ..< _columns { 22 | let sourceIndex = c * _rows + r 23 | let targetIndex = r * _columns + c 24 | transposedElements[targetIndex] = elements[sourceIndex] 25 | } 26 | } 27 | } 28 | } 29 | elements = transposedElements 30 | } 31 | swap(&_rows, &_columns) 32 | } 33 | 34 | var transpose : Matrix { 35 | var m = self 36 | m.transposeInPlace() 37 | return m 38 | } 39 | 40 | internal mutating func adjointInPlace() { 41 | var transposedElements = elements 42 | asPointer(elements) { elements in 43 | asMutablePointer(&transposedElements) { transposedElements in 44 | for r in 0 ..< _rows { 45 | for c in 0 ..< _columns { 46 | let sourceIndex = c * _rows + r 47 | let targetIndex = r * _columns + c 48 | transposedElements[targetIndex] = elements[sourceIndex].adjoint 49 | } 50 | } 51 | } 52 | } 53 | elements = transposedElements 54 | swap(&_rows, &_columns) 55 | } 56 | 57 | var adjoint: Matrix { 58 | var m = self 59 | m.adjointInPlace() 60 | return m 61 | } 62 | 63 | func column(_ c : Int) -> Matrix { 64 | precondition(c >= 0 && c < _columns) 65 | let start = c * _rows 66 | return Matrix(Array(elements[start ..< start + _rows])) 67 | } 68 | 69 | func row(_ r : Int) -> Matrix { 70 | precondition(r >= 0 && r < _rows) 71 | let elems = (0 ..< _columns).map { c in self[r, c] } 72 | return Matrix(row: elems) 73 | } 74 | 75 | mutating func reshape(rows : Int, columns : Int) { 76 | precondition(rows * columns == count) 77 | self._rows = rows 78 | self._columns = columns 79 | } 80 | 81 | func reshaped(rows : Int, columns : Int) -> Matrix { 82 | var A = self 83 | A.reshape(rows: rows, columns: columns) 84 | return A 85 | } 86 | 87 | mutating func extend(rows : Int, columns : Int, with : Element = .zero) { 88 | guard rows > _rows || columns > _columns else { return } 89 | var result = Matrix(repeating: with, rows: max(_rows, rows), columns: max(_columns, columns)) 90 | result[0 ..< _rows, 0 ..< _columns] = self 91 | self = result 92 | } 93 | 94 | mutating func extend(rows : Int, with : Element = .zero) { 95 | extend(rows: rows, columns: columns, with: with) 96 | } 97 | 98 | mutating func extend(columns : Int, with : Element = .zero) { 99 | extend(rows: rows, columns: columns, with: with) 100 | } 101 | 102 | /// - todo: This is a naive implementation, needs to be optimized. 103 | subscript (rowIndices : R, columnIndices : C) -> Matrix where R.Element == Int, C.Element == Int { 104 | get { 105 | var elems : [Element] = [] 106 | for c in columnIndices { 107 | for r in rowIndices { 108 | elems.append(self[r, c]) 109 | } 110 | } 111 | return Matrix(rows: rowIndices.count, columns: columnIndices.count, elements: elems) 112 | } 113 | set { 114 | precondition(newValue.rows == rowIndices.count && newValue.columns == columnIndices.count) 115 | var index = 0 116 | let elems = newValue.elements 117 | for c in columnIndices { 118 | for r in rowIndices { 119 | self[r, c] = elems[index] 120 | index += 1 121 | } 122 | } 123 | } 124 | } 125 | 126 | init(columns : [Vector]) { 127 | var matrix = BlockMatrix(rows : 1, columns : columns.count) 128 | for (i, column) in columns.enumerated() { 129 | matrix[0, i] = Matrix(column) 130 | } 131 | self = flatten(matrix) 132 | } 133 | 134 | init(rows : [Vector]) { 135 | var matrix = BlockMatrix(rows : rows.count, columns : 1) 136 | for (i, row) in rows.enumerated() { 137 | matrix[i, 0] = Matrix(row: row) 138 | } 139 | self = flatten(matrix) 140 | } 141 | 142 | init(stackHorizontally stack: [Matrix]) { 143 | var matrix = BlockMatrix(rows : 1, columns : stack.count) 144 | for (i, m) in stack.enumerated() { 145 | matrix[0, i] = m 146 | } 147 | self = flatten(matrix) 148 | } 149 | 150 | init(stackVertically stack: [Matrix]) { 151 | var matrix = BlockMatrix(rows : stack.count, columns : 1) 152 | for (i, m) in stack.enumerated() { 153 | matrix[i, 0] = m 154 | } 155 | self = flatten(matrix) 156 | } 157 | 158 | var isQuasiUpperTriangle : Bool { 159 | let n = rows 160 | for c in 0 ..< columns { 161 | var r = c + 2 162 | while r < n { 163 | if self[r, c] != .zero { return false } 164 | r += 1 165 | } 166 | } 167 | return true 168 | } 169 | 170 | var isUpperTriangle : Bool { 171 | let n = rows 172 | for c in 0 ..< columns { 173 | var r = c + 1 174 | while r < n { 175 | if self[r, c] != .zero { return false } 176 | r += 1 177 | } 178 | } 179 | return true 180 | } 181 | 182 | 183 | } 184 | 185 | public func flatten(_ matrix : BlockMatrix) -> Matrix { 186 | var rowHeights = [Int](repeating: 0, count: matrix.rows) 187 | var columnWidths = [Int](repeating: 0, count: matrix.columns) 188 | var totalRows = 0 189 | var totalColumns = 0 190 | for r in 0 ..< matrix.rows { 191 | var height = 0 192 | for c in 0 ..< matrix.columns { 193 | height = max(height, matrix[r, c].rows) 194 | } 195 | rowHeights[r] = height 196 | totalRows += height 197 | } 198 | for c in 0 ..< matrix.columns { 199 | var width = 0 200 | for r in 0 ..< matrix.rows { 201 | width = max(width, matrix[r, c].columns) 202 | } 203 | columnWidths[c] = width 204 | totalColumns += width 205 | } 206 | var result = Matrix(rows: totalRows, columns: totalColumns) 207 | var targetColumn = 0 208 | for c in 0 ..< matrix.columns { 209 | var targetRow = 0 210 | for r in 0 ..< matrix.rows { 211 | let m = matrix[r, c] 212 | result[targetRow ..< targetRow + m.rows, targetColumn ..< targetColumn + m.columns] = m 213 | targetRow += rowHeights[r] 214 | } 215 | targetColumn += columnWidths[c] 216 | } 217 | return result 218 | } 219 | 220 | -------------------------------------------------------------------------------- /Sources/LANumerics/ToStringWithPrecision.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Numerics 3 | 4 | public protocol ToStringWithPrecision { 5 | 6 | func toString(precision : Int?) -> String 7 | 8 | } 9 | 10 | extension Float : ToStringWithPrecision { 11 | 12 | public func toString(precision : Int? = nil) -> String { 13 | if let precision = precision { 14 | return String(format: "%.\(precision)f", self) 15 | } else { 16 | return self.description 17 | } 18 | } 19 | 20 | } 21 | 22 | extension Double : ToStringWithPrecision { 23 | 24 | public func toString(precision : Int? = nil) -> String { 25 | if let precision = precision { 26 | return String(format: "%.\(precision)f", self) 27 | } else { 28 | return self.description 29 | } 30 | } 31 | 32 | } 33 | 34 | extension Complex : ToStringWithPrecision { 35 | 36 | public func toString(precision : Int? = nil) -> String { 37 | return Complex.dispatch( 38 | float: { 39 | if imaginary.isZero { 40 | let x = (real as! Float).toString(precision: precision) 41 | return x 42 | } else if real.isZero { 43 | let y = (imaginary as! Float).toString(precision: precision) 44 | return "\(y)i" 45 | } else if imaginary > 0 { 46 | let x = (real as! Float).toString(precision: precision) 47 | let y = (imaginary as! Float).toString(precision: precision) 48 | return "\(x) + \(y)i" 49 | } else { 50 | let x = (real as! Float).toString(precision: precision) 51 | let y = (-imaginary as! Float).toString(precision: precision) 52 | return "\(x) - \(y)i" 53 | } 54 | }, 55 | double: { 56 | if imaginary.isZero { 57 | let x = (real as! Double).toString(precision: precision) 58 | return x 59 | } else if real.isZero { 60 | let y = (imaginary as! Double).toString(precision: precision) 61 | return "\(y)i" 62 | } else if imaginary > 0 { 63 | let x = (real as! Double).toString(precision: precision) 64 | let y = (imaginary as! Double).toString(precision: precision) 65 | return "\(x) + \(y)i" 66 | } else { 67 | let x = (real as! Double).toString(precision: precision) 68 | let y = (-imaginary as! Double).toString(precision: precision) 69 | return "\(x) - \(y)i" 70 | } 71 | } 72 | ) 73 | } 74 | 75 | } 76 | 77 | extension Matrix : ToStringWithPrecision, CustomStringConvertible where Element : ToStringWithPrecision { 78 | 79 | private func left(row : Int) -> String { 80 | guard rows > 1 else { return "(" } 81 | if row == 0 { return "⎛" } 82 | if row == rows - 1 { return "⎝" } 83 | return "⎜" 84 | } 85 | 86 | private func right(row : Int) -> String { 87 | guard rows > 1 else { return ")" } 88 | if row == 0 { return "⎞" } 89 | if row == rows - 1 { return "⎠" } 90 | return "⎟" 91 | } 92 | 93 | private func extend(_ s : String, width : Int) -> String { 94 | var t = s 95 | while t.count < width { 96 | t.append(" ") 97 | } 98 | return t 99 | } 100 | 101 | public func toString(precision : Int? = nil) -> String { 102 | var column_widths = [Int](repeating: 0, count: columns) 103 | for c in 0 ..< columns { 104 | var W = 0 105 | for r in 0 ..< rows { 106 | let width = self[r, c].toString(precision: precision).count 107 | W = max(width, W) 108 | } 109 | column_widths[c] = W 110 | } 111 | var s : String = "" 112 | for r in 0 ..< rows { 113 | if r > 0 { s.append("\n") } 114 | s.append(left(row: r)) 115 | for c in 0 ..< columns { 116 | if c > 0 { s.append(" ") } 117 | s.append(extend(self[r, c].toString(precision: precision), width: column_widths[c])) 118 | } 119 | s.append(right(row: r)) 120 | } 121 | return s 122 | } 123 | 124 | public var description: String { 125 | if _rows == 0 || _columns == 0 { 126 | return "\(_rows)x\(_columns)-matrix" 127 | } else { 128 | return "\(_rows)x\(_columns)-matrix:\n\(toString(precision: nil))" 129 | } 130 | } 131 | 132 | } 133 | 134 | extension Vector : ToStringWithPrecision where Element : ToStringWithPrecision { 135 | 136 | public func toString(precision : Int? = nil) -> String { 137 | var s : String = "[" 138 | var first = true 139 | for elem in self { 140 | if first { 141 | first = false 142 | } else { 143 | s.append(", ") 144 | } 145 | s.append(elem.toString(precision: precision)) 146 | } 147 | s.append("]") 148 | return s 149 | } 150 | 151 | } 152 | -------------------------------------------------------------------------------- /Tests/LANumericsTests/LANumericsTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import LANumerics 3 | import Numerics 4 | import simd 5 | 6 | final class LANumericsTests: XCTestCase { 7 | 8 | public typealias Num = LANumeric 9 | 10 | func countingMatrix(rows : Int, columns : Int) -> Matrix { 11 | return Matrix(rows: rows, columns: columns) { r, c in 12 | return F(exactly: c * rows + r + 1)! 13 | } 14 | } 15 | 16 | func randomWhole() -> F { 17 | F.randomWhole(in: -100 ... 100) 18 | } 19 | 20 | func randomWholeMatrix(rows : Int = Int.random(in: 0 ... 10), columns : Int = Int.random(in: 0 ... 10)) -> Matrix { 21 | return Matrix(rows: rows, columns: columns) { _ , _ in 22 | randomWhole() 23 | } 24 | } 25 | 26 | func randomWholeVector(count : Int = Int.random(in: 0 ... 10)) -> Vector { 27 | var X : Vector = [] 28 | for _ in 0 ..< count { 29 | X.append(randomWhole()) 30 | } 31 | return X 32 | } 33 | 34 | func stress(iterations : Int = 1000, _ test : () -> Void) { 35 | for _ in 0 ..< iterations { 36 | test() 37 | } 38 | } 39 | 40 | func testTranspose() { 41 | let u : Matrix = countingMatrix(rows : 4, columns : 3) 42 | let v = u.transpose 43 | XCTAssertEqual(u.rows, 4) 44 | XCTAssertEqual(u.columns, 3) 45 | XCTAssertEqual(v.rows, 3) 46 | XCTAssertEqual(v.columns, 4) 47 | for r in 0 ..< u.rows { 48 | for c in 0 ..< u.columns { 49 | XCTAssertEqual(u[r, c], v[c, r]) 50 | } 51 | } 52 | XCTAssertEqual(v.transpose, u) 53 | XCTAssertEqual(v, u′) 54 | } 55 | 56 | func testManhattanNorm() { 57 | func add(_ n : Int) -> Int { n * (n + 1) / 2 } 58 | func generic(_ type : E.Type) { 59 | let u : Matrix = countingMatrix(rows : 4, columns : 3) 60 | XCTAssertEqual(u.manhattanNorm, E.Magnitude(exactly: add(u.rows * u.columns))!) 61 | XCTAssertEqual(u.manhattanNorm, u.reduce(0) { x, y in x + y.manhattanLength }) 62 | let w : Matrix = randomWholeMatrix() 63 | XCTAssertEqual(w.manhattanNorm, w.reduce(0) { x, y in x + y.manhattanLength }) 64 | } 65 | stress { 66 | generic(Float.self) 67 | generic(Double.self) 68 | generic(Complex.self) 69 | generic(Complex.self) 70 | } 71 | } 72 | 73 | func testNorm() { 74 | func generic(_ type : E.Type) { 75 | let u : Matrix = randomWholeMatrix() 76 | let l2 = u.norm 77 | let sum = u.reduce(0) { x, y in x + y.lengthSquared } 78 | XCTSame(l2 * l2, sum) 79 | } 80 | stress { 81 | generic(Float.self) 82 | generic(Double.self) 83 | generic(Complex.self) 84 | generic(Complex.self) 85 | } 86 | } 87 | 88 | func testScaleAndAddFloat() { 89 | func generic(_ type : E.Type) { 90 | let m = Int.random(in: 1 ... 10) 91 | let n = Int.random(in: 1 ... 10) 92 | let u : Matrix = randomWholeMatrix(rows: m, columns: n) 93 | let v : Matrix = randomWholeMatrix(rows: m, columns: n) 94 | let alpha : E = randomWhole() 95 | let beta : E = randomWhole() 96 | var result = u 97 | result.accumulate(alpha, beta, v) 98 | let spec = u.combine(v) { x, y in alpha * x + beta * y} 99 | XCTAssertEqual(result, spec) 100 | XCTAssertEqual(u + v, u.combine(v, { x, y in x + y })) 101 | XCTAssertEqual(u - v, u.combine(v, { x, y in x - y })) 102 | XCTAssertEqual(u + .zeros(m, n), u) 103 | XCTAssertEqual(.zeros(m, n) + u, u) 104 | } 105 | stress { 106 | generic(Float.self) 107 | generic(Double.self) 108 | generic(Complex.self) 109 | generic(Complex.self) 110 | } 111 | } 112 | 113 | func testInfNormManhattan() { 114 | func generic(_ type : E.Type) { 115 | let u : Matrix = randomWholeMatrix() 116 | let norm = u.infNormManhattan 117 | XCTAssert(u.forall { x in norm >= x.manhattanLength }, "norm = \(norm) of \(u)") 118 | XCTAssert((u.vector.isEmpty && norm == 0) || u.exists { x in norm == x.manhattanLength }, "norm = \(norm) of \(u)") 119 | } 120 | stress { 121 | generic(Float.self) 122 | generic(Double.self) 123 | generic(Complex.self) 124 | generic(Complex.self) 125 | } 126 | } 127 | 128 | func testInfNorm() { 129 | func generic(_ type : E.Type) { 130 | let u : Matrix = randomWholeMatrix() 131 | let norm = u.infNorm 132 | XCTAssert(u.forall { x in norm >= x.magnitude }, "norm = \(norm) of \(u)") 133 | XCTAssert((u.vector.isEmpty && norm == 0) || u.exists { x in norm == x.magnitude }, "norm = \(norm) of \(u)") 134 | } 135 | stress { 136 | generic(Float.self) 137 | generic(Double.self) 138 | generic(Complex.self) 139 | generic(Complex.self) 140 | } 141 | } 142 | 143 | func scale(_ alpha : E, _ vec : Vector) -> Vector { 144 | return vec.map { x in alpha * x } 145 | } 146 | 147 | func scale(_ alpha : E, _ matrix : Matrix) -> Matrix { 148 | return matrix.map { x in alpha * x } 149 | } 150 | 151 | func mul(_ A : Matrix, _ B : Matrix) -> Matrix { 152 | let M = A.rows 153 | let N = B.columns 154 | let K = A.columns 155 | precondition(K == B.rows) 156 | var C = Matrix(rows: M, columns: N) 157 | for m in 0 ..< M { 158 | for n in 0 ..< N { 159 | var sum : E = 0 160 | for k in 0 ..< K { 161 | sum += A[m, k] * B[k, n] 162 | } 163 | C[m, n] = sum 164 | } 165 | } 166 | return C 167 | } 168 | 169 | func dot(_ X : Vector, _ Y : Vector) -> E { 170 | precondition(X.count == Y.count) 171 | var sum : E = 0 172 | for i in 0 ..< X.count { 173 | sum += X[i] * Y[i] 174 | } 175 | return sum 176 | } 177 | 178 | func epsilon(_ type : E.Type) -> E.Magnitude { 179 | let e : E = 0.1 180 | return e.magnitude 181 | } 182 | 183 | func XCTSame(_ X : Matrix, _ Y : Matrix) { 184 | let norm = (X - Y).infNorm 185 | XCTAssert(norm < epsilon(E.self), "norm is \(norm), X = \(X), Y = \(Y)") 186 | } 187 | 188 | func XCTSame(_ X : E, _ Y : E) { 189 | let norm = (X - Y).magnitude 190 | let e : E.Magnitude = epsilon(E.self) 191 | XCTAssert(norm < e, "norm is \(norm), X = \(X), Y = \(Y)") 192 | } 193 | 194 | func XCTSame(_ X : Vector, _ Y : Vector) { 195 | XCTSame(Matrix(X), Matrix(Y)) 196 | } 197 | 198 | func testScale() { 199 | func generic(_ type : E.Type) { 200 | var X : Vector = randomWholeVector() 201 | let alpha : E = randomWhole() 202 | let Y = scale(alpha, X) 203 | E.scaleVector(alpha, &X) 204 | XCTAssertEqual(X, Y) 205 | X = [] 206 | E.scaleVector(alpha, &X) 207 | XCTAssertEqual(X, []) 208 | let A : Matrix = randomWholeMatrix() 209 | XCTAssertEqual(alpha * A, scale(alpha, A)) 210 | } 211 | stress { 212 | generic(Float.self) 213 | generic(Double.self) 214 | generic(Complex.self) 215 | generic(Complex.self) 216 | } 217 | } 218 | 219 | func testDotProduct() { 220 | func generic(_ type : E.Type) { 221 | let X : Vector = randomWholeVector() 222 | let Y : Vector = randomWholeVector(count: X.count) 223 | XCTAssertEqual(E.dotProduct(X, Y), dot(X, Y)) 224 | XCTAssertEqual(X * Y, dot(X, Y)) 225 | XCTAssertEqual(E.adjointDotProduct(X, Y), dot(X′.vector, Y)) 226 | XCTAssertEqual(X ′* Y, dot(X′.vector, Y)) 227 | } 228 | stress { 229 | generic(Float.self) 230 | generic(Double.self) 231 | generic(Complex.self) 232 | generic(Complex.self) 233 | } 234 | } 235 | 236 | func testMatrixProduct() { 237 | func generic(_ type : E.Type) { 238 | let M = Int.random(in: 0 ... 10) 239 | let N = Int.random(in: 0 ... 10) 240 | let K = Int.random(in: 0 ... 10) 241 | let A : Matrix = randomWholeMatrix(rows: M, columns: K) 242 | let B : Matrix = randomWholeMatrix(rows: K, columns: N) 243 | XCTAssertEqual(A * B, mul(A, B)) 244 | XCTAssertEqual(A′ ′* B, mul(A, B)) 245 | XCTAssertEqual(A *′ B′, mul(A, B)) 246 | XCTAssertEqual(A′ ′*′ B′, mul(A, B)) 247 | let C : Matrix = randomWholeMatrix(rows: M, columns: N) 248 | let alpha : E = randomWhole() 249 | let beta : E = randomWhole() 250 | let R = scale(alpha, mul(A, B)) + scale(beta, C) 251 | func test(transposeA : Transpose, transposeB : Transpose) { 252 | let opA = transposeA.apply(A) 253 | let opB = transposeB.apply(B) 254 | var D = C 255 | E.matrixProduct(alpha, transposeA, opA, transposeB, opB, beta, &D) 256 | XCTAssertEqual(D, R) 257 | } 258 | test(transposeA: .none, transposeB: .none) 259 | test(transposeA: .transpose, transposeB: .none) 260 | test(transposeA: .adjoint, transposeB: .none) 261 | test(transposeA: .none, transposeB: .transpose) 262 | test(transposeA: .transpose, transposeB: .transpose) 263 | test(transposeA: .adjoint, transposeB: .transpose) 264 | test(transposeA: .none, transposeB: .adjoint) 265 | test(transposeA: .transpose, transposeB: .adjoint) 266 | test(transposeA: .adjoint, transposeB: .adjoint) 267 | } 268 | stress { 269 | generic(Float.self) 270 | generic(Double.self) 271 | generic(Complex.self) 272 | generic(Complex.self) 273 | } 274 | } 275 | 276 | func testMatrixVectorProduct() { 277 | func generic(_ type : E.Type) { 278 | let M = Int.random(in: 0 ... 10) 279 | let N = 1 280 | let K = Int.random(in: 0 ... 10) 281 | let A : Matrix = randomWholeMatrix(rows: M, columns: K) 282 | let B : Matrix = randomWholeMatrix(rows: K, columns: N) 283 | XCTAssertEqual(A * B.vector, mul(A, B).vector) 284 | XCTAssertEqual(A′ ′* B.vector, mul(A, B).vector) 285 | let C : Matrix = randomWholeMatrix(rows: M, columns: N) 286 | let alpha : E = randomWhole() 287 | let beta : E = randomWhole() 288 | let R = scale(alpha, mul(A, B)) + scale(beta, C) 289 | func test(transpose : Transpose) { 290 | let opA = transpose.apply(A) 291 | let X = B.vector 292 | var Y = C.vector 293 | E.matrixVectorProduct(alpha, transpose, opA, X, beta, &Y) 294 | XCTAssertEqual(Y, R.vector) 295 | } 296 | test(transpose: .none) 297 | test(transpose: .transpose) 298 | test(transpose: .adjoint) 299 | } 300 | stress { 301 | generic(Float.self) 302 | generic(Double.self) 303 | generic(Complex.self) 304 | generic(Complex.self) 305 | } 306 | } 307 | 308 | func testVectorAdjointVectorProduct() { 309 | func generic(_ type : E.Type) { 310 | let X : Matrix = randomWholeMatrix(rows: Int.random(in: 0 ... 10), columns: 1) 311 | let Y : Matrix = randomWholeMatrix(rows: Int.random(in: 0 ... 10), columns: 1) 312 | XCTAssertEqual(X.vector *′ Y.vector, mul(X, Y′)) 313 | var A : Matrix = randomWholeMatrix(rows: X.rows, columns: Y.rows) 314 | let alpha : E = randomWhole() 315 | let R = scale(alpha, mul(X, Y′)) + A 316 | E.vectorAdjointVectorProduct(alpha, X.vector, Y.vector, &A) 317 | XCTAssertEqual(A, R) 318 | } 319 | stress { 320 | generic(Float.self) 321 | generic(Double.self) 322 | generic(Complex.self) 323 | generic(Complex.self) 324 | } 325 | } 326 | 327 | func testVectorVectorProduct() { 328 | func generic(_ type : E.Type) { 329 | let X : Matrix = randomWholeMatrix(rows: Int.random(in: 0 ... 10), columns: 1) 330 | let Y : Matrix = randomWholeMatrix(rows: Int.random(in: 0 ... 10), columns: 1) 331 | var A : Matrix = randomWholeMatrix(rows: X.rows, columns: Y.rows) 332 | let alpha : E = randomWhole() 333 | let R = scale(alpha, mul(X, Y.transpose)) + A 334 | E.vectorVectorProduct(alpha, X.vector, Y.vector, &A) 335 | XCTAssertEqual(A, R) 336 | } 337 | stress { 338 | generic(Float.self) 339 | generic(Double.self) 340 | generic(Complex.self) 341 | generic(Complex.self) 342 | } 343 | } 344 | 345 | func testSIMDVectors() { 346 | func generic(_ type : E.Type) { 347 | func test(_ count : Int, transform : (Matrix) -> Matrix) { 348 | let m : Matrix = randomWholeMatrix(rows: count, columns: 1) 349 | XCTAssertEqual(m, transform(m)) 350 | } 351 | test(2) { m in Matrix(m.simd2) } 352 | test(2) { m in Matrix(row: m.simd2)′ } 353 | test(3) { m in Matrix(m.simd3) } 354 | test(3) { m in Matrix(row: m.simd3)′ } 355 | test(4) { m in Matrix(m.simd4) } 356 | test(4) { m in Matrix(row: m.simd4)′ } 357 | test(8) { m in Matrix(m.simd8) } 358 | test(8) { m in Matrix(row: m.simd8)′ } 359 | test(16) { m in Matrix(m.simd16) } 360 | test(16) { m in Matrix(row: m.simd16)′ } 361 | test(32) { m in Matrix(m.simd32) } 362 | test(32) { m in Matrix(row: m.simd32)′ } 363 | test(64) { m in Matrix(m.simd64) } 364 | test(64) { m in Matrix(row: m.simd64)′ } 365 | } 366 | stress { 367 | generic(Float.self) 368 | generic(Double.self) 369 | } 370 | } 371 | 372 | func testSIMDMatricesFloat() { 373 | typealias E = Float 374 | 375 | stress { 376 | let v2 : Matrix = randomWholeMatrix(rows: 2, columns: 1) 377 | let m2x2 : Matrix = randomWholeMatrix(rows: 2, columns: 2) 378 | XCTAssertEqual(m2x2, Matrix(m2x2.simd2x2)) 379 | XCTAssertEqual((m2x2 * v2).simd2, m2x2.simd2x2 * v2.simd2) 380 | let m3x2 : Matrix = randomWholeMatrix(rows: 3, columns: 2) 381 | XCTAssertEqual(m3x2, Matrix(m3x2.simd2x3)) 382 | XCTAssertEqual((m3x2 * v2).simd3, m3x2.simd2x3 * v2.simd2) 383 | let m4x2 : Matrix = randomWholeMatrix(rows: 4, columns: 2) 384 | XCTAssertEqual(m4x2, Matrix(m4x2.simd2x4)) 385 | XCTAssertEqual((m4x2 * v2).simd4, m4x2.simd2x4 * v2.simd2) 386 | 387 | let v3 : Matrix = randomWholeMatrix(rows: 3, columns: 1) 388 | let m2x3 : Matrix = randomWholeMatrix(rows: 2, columns: 3) 389 | XCTAssertEqual(m2x3, Matrix(m2x3.simd3x2)) 390 | XCTAssertEqual((m2x3 * v3).simd2, m2x3.simd3x2 * v3.simd3) 391 | let m3x3 : Matrix = randomWholeMatrix(rows: 3, columns: 3) 392 | XCTAssertEqual(m3x3, Matrix(m3x3.simd3x3)) 393 | XCTAssertEqual((m3x3 * v3).simd3, m3x3.simd3x3 * v3.simd3) 394 | let m4x3 : Matrix = randomWholeMatrix(rows: 4, columns: 3) 395 | XCTAssertEqual(m4x3, Matrix(m4x3.simd3x4)) 396 | XCTAssertEqual((m4x3 * v3).simd4, m4x3.simd3x4 * v3.simd3) 397 | 398 | let v4 : Matrix = randomWholeMatrix(rows: 4, columns: 1) 399 | let m2x4 : Matrix = randomWholeMatrix(rows: 2, columns: 4) 400 | XCTAssertEqual(m2x4, Matrix(m2x4.simd4x2)) 401 | XCTAssertEqual((m2x4 * v4).simd2, m2x4.simd4x2 * v4.simd4) 402 | let m3x4 : Matrix = randomWholeMatrix(rows: 3, columns: 4) 403 | XCTAssertEqual(m3x4, Matrix(m3x4.simd4x3)) 404 | XCTAssertEqual((m3x4 * v4).simd3, m3x4.simd4x3 * v4.simd4) 405 | let m4x4 : Matrix = randomWholeMatrix(rows: 4, columns: 4) 406 | XCTAssertEqual(m4x4, Matrix(m4x4.simd4x4)) 407 | XCTAssertEqual((m4x4 * v4).simd4, m4x4.simd4x4 * v4.simd4) 408 | } 409 | } 410 | 411 | func testSIMDMatricesDouble() { 412 | typealias E = Double 413 | 414 | stress { 415 | let v2 : Matrix = randomWholeMatrix(rows: 2, columns: 1) 416 | let m2x2 : Matrix = randomWholeMatrix(rows: 2, columns: 2) 417 | XCTAssertEqual(m2x2, Matrix(m2x2.simd2x2)) 418 | XCTAssertEqual((m2x2 * v2).simd2, m2x2.simd2x2 * v2.simd2) 419 | let m3x2 : Matrix = randomWholeMatrix(rows: 3, columns: 2) 420 | XCTAssertEqual(m3x2, Matrix(m3x2.simd2x3)) 421 | XCTAssertEqual((m3x2 * v2).simd3, m3x2.simd2x3 * v2.simd2) 422 | let m4x2 : Matrix = randomWholeMatrix(rows: 4, columns: 2) 423 | XCTAssertEqual(m4x2, Matrix(m4x2.simd2x4)) 424 | XCTAssertEqual((m4x2 * v2).simd4, m4x2.simd2x4 * v2.simd2) 425 | 426 | let v3 : Matrix = randomWholeMatrix(rows: 3, columns: 1) 427 | let m2x3 : Matrix = randomWholeMatrix(rows: 2, columns: 3) 428 | XCTAssertEqual(m2x3, Matrix(m2x3.simd3x2)) 429 | XCTAssertEqual((m2x3 * v3).simd2, m2x3.simd3x2 * v3.simd3) 430 | let m3x3 : Matrix = randomWholeMatrix(rows: 3, columns: 3) 431 | XCTAssertEqual(m3x3, Matrix(m3x3.simd3x3)) 432 | XCTAssertEqual((m3x3 * v3).simd3, m3x3.simd3x3 * v3.simd3) 433 | let m4x3 : Matrix = randomWholeMatrix(rows: 4, columns: 3) 434 | XCTAssertEqual(m4x3, Matrix(m4x3.simd3x4)) 435 | XCTAssertEqual((m4x3 * v3).simd4, m4x3.simd3x4 * v3.simd3) 436 | 437 | let v4 : Matrix = randomWholeMatrix(rows: 4, columns: 1) 438 | let m2x4 : Matrix = randomWholeMatrix(rows: 2, columns: 4) 439 | XCTAssertEqual(m2x4, Matrix(m2x4.simd4x2)) 440 | XCTAssertEqual((m2x4 * v4).simd2, m2x4.simd4x2 * v4.simd4) 441 | let m3x4 : Matrix = randomWholeMatrix(rows: 3, columns: 4) 442 | XCTAssertEqual(m3x4, Matrix(m3x4.simd4x3)) 443 | XCTAssertEqual((m3x4 * v4).simd3, m3x4.simd4x3 * v4.simd4) 444 | let m4x4 : Matrix = randomWholeMatrix(rows: 4, columns: 4) 445 | XCTAssertEqual(m4x4, Matrix(m4x4.simd4x4)) 446 | XCTAssertEqual((m4x4 * v4).simd4, m4x4.simd4x4 * v4.simd4) 447 | } 448 | } 449 | 450 | func testShape() { 451 | let a = Matrix.init(repeating: 1, rows: 1, columns: 2) 452 | let b = Matrix.init(repeating: 2, rows: 3, columns: 1) 453 | let c : Matrix = (1 / 100) * countingMatrix(rows: 4, columns: 3) + Matrix(repeating: 3, rows: 4, columns: 3) 454 | let d = Matrix.init(repeating: 4, rows: 2, columns: 2) 455 | let m = flatten(Matrix(rows: 2, columns: 2, elements: [a, c, b, d])) 456 | let col1 : Vector = [1.0, 0.0, 0.0, 3.01, 3.02, 3.03, 3.04] 457 | let col2 : Vector = [1.0, 0.0, 0.0, 3.05, 3.06, 3.07, 3.08] 458 | let col3 : Vector = [0.0, 0.0, 0.0, 3.09, 3.1, 3.11, 3.12] 459 | let col4 : Vector = [2.0, 2.0, 2.0, 4.0, 4.0] 460 | let col5 : Vector = [0.0, 0.0, 0.0, 4.0, 4.0] 461 | XCTAssertEqual(m, Matrix(columns: [col1, col2, col3, col4, col5])) 462 | XCTAssertEqual(m, Matrix(stackHorizontally: [Matrix(col1), Matrix(col2), Matrix(col3), Matrix(col4), Matrix(col5)])) 463 | let rows = (0 ..< m.rows).map { r in m.row(r).vector } 464 | XCTAssertEqual(m, Matrix(rows: rows)) 465 | XCTAssertEqual(m, Matrix(stackVertically: (0 ..< m.rows).map { r in m.row(r) })) 466 | } 467 | 468 | func testSolveLinearEquations() { 469 | func generic(_ type : E.Type) { 470 | let A = Matrix(rows: [[7, 5, -3], [3, -5, 2], [5, 3, -7]]) 471 | let B = Matrix([16, -8, 0]) 472 | let X = Matrix([1, 3, 2]) 473 | let eps = epsilon(E.self) 474 | XCTAssert((A.solve(B)! - X).infNorm < eps) 475 | let Z = Matrix(rows: 3, columns: 3) 476 | XCTAssertEqual(Z.solve(B), nil) 477 | XCTAssertEqual(Z.solve([0, 0, 0]), nil) 478 | XCTAssertEqual(A.solve([0, 0, 0])!, [0, 0, 0]) 479 | } 480 | generic(Float.self) 481 | generic(Double.self) 482 | generic(Complex.self) 483 | generic(Complex.self) 484 | } 485 | 486 | func testSolveLinearLeastSquares() { 487 | func generic(_ type : E.Type) { 488 | let A = Matrix(rows: [[7, 5, -3], [3, -5, 2], [5, 3, -7]]) 489 | let B = Matrix([16, -8, 0]) 490 | let X = Matrix([1, 3, 2]) 491 | let eps = epsilon(E.self) 492 | XCTAssert((A ∖ B - X).infNorm < eps) 493 | XCTAssert((A′ ′∖ B - X).infNorm < eps) 494 | let Z = Matrix(rows: 3, columns: 3) 495 | XCTAssertEqual(Z ∖ B, Matrix.zeros(3, 1)) 496 | XCTAssertEqual(Z ∖ [0, 0, 0], [0, 0, 0]) 497 | XCTAssertEqual(A ∖ [0, 0, 0], [0, 0, 0]) 498 | XCTAssertEqual(Matrix() ∖ [], []) 499 | } 500 | generic(Float.self) 501 | generic(Double.self) 502 | generic(Complex.self) 503 | generic(Complex.self) 504 | } 505 | 506 | func testLäuchliExample() { 507 | func generic(eps : E) { 508 | let A = Matrix(rows: [[1, 1], [eps, 0], [0, eps]]) 509 | let b = [2, eps, eps] 510 | XCTAssertNil((A′*A).solve(A′*b)) 511 | XCTAssert((A ∖ Matrix(b) - Matrix([1, 1])).infNorm < 10 * eps) 512 | XCTAssert((A′ ′∖ Matrix(b) - Matrix([1, 1])).infNorm < 10 * eps) 513 | } 514 | generic(eps: Double(1e-16)) 515 | generic(eps: Float(1e-7)) 516 | } 517 | 518 | func testSingularValueDecomposition() { 519 | func generic(_ type : E.Type) { 520 | func same(_ X : Matrix, _ Y : Matrix) { 521 | let norm = (X - Y).infNorm 522 | XCTAssert(norm < epsilon(E.self), "norm is \(norm), X = \(X), Y = \(Y)") 523 | } 524 | func isSame(_ X : Matrix, _ Y : Matrix) -> Bool { 525 | let norm = (X - Y).infNorm 526 | return norm < epsilon(E.self) 527 | } 528 | let A : Matrix = randomWholeMatrix() 529 | let m = A.rows 530 | let n = A.columns 531 | let k = min(m, n) 532 | let svd = A.svd()! 533 | XCTAssertEqual(svd.singularValues.count, k) 534 | XCTAssert(svd.left.hasDimensions(m, m)) 535 | XCTAssert(svd.right.hasDimensions(n, n)) 536 | same(svd.left ′* svd.left, .eye(m)) 537 | same(svd.right ′* svd.right, .eye(n)) 538 | func map(_ v : Vector) -> Vector { 539 | v.map { x in E(magnitude: x) } 540 | } 541 | let D = Matrix(rows: A.rows, columns: A.columns, diagonal: map(svd.singularValues)) 542 | same(svd.left * D * svd.right, A) 543 | let svdS = A.svd(left: .singular, right: .singular)! 544 | same(Matrix(map(svd.singularValues)), Matrix(map(svdS.singularValues))) 545 | same(svd.left[0 ..< m, 0 ..< k], svdS.left) 546 | same(svd.right[0 ..< k, 0 ..< n], svdS.right) 547 | let svdN = A.svd(left: .none, right: .none)! 548 | same(Matrix(map(svd.singularValues)), Matrix(map(svdN.singularValues))) 549 | same(svd.left[0 ..< m, 0 ..< 0], svdN.left) 550 | same(svd.right[0 ..< 0, 0 ..< n], svdN.right) 551 | } 552 | stress { 553 | generic(Float.self) 554 | generic(Double.self) 555 | generic(Complex.self) 556 | generic(Complex.self) 557 | } 558 | } 559 | 560 | func test_blas_asum() { 561 | func generic(_ type : E.Type) { 562 | let v : Vector = randomWholeVector() 563 | let asum = Matrix(v).reduce(0) { x, y in x + y.manhattanLength } 564 | let blas_asum = E.blas_asum(Int32(v.count), v, 1) 565 | XCTAssertEqual(asum, blas_asum) 566 | } 567 | stress { 568 | generic(Float.self) 569 | generic(Double.self) 570 | generic(Complex.self) 571 | generic(Complex.self) 572 | } 573 | } 574 | 575 | func test_blas_nrm2() { 576 | func generic(_ type : E.Type) { 577 | let v : Vector = randomWholeVector() 578 | let nrm2_squared = Matrix(v).reduce(0) { x, y in x + y.lengthSquared } 579 | let blas_nrm2 = E.blas_nrm2(Int32(v.count), v, 1) 580 | XCTSame(E(magnitude: nrm2_squared), E(magnitude: blas_nrm2 * blas_nrm2)) 581 | } 582 | stress { 583 | generic(Float.self) 584 | generic(Double.self) 585 | generic(Complex.self) 586 | generic(Complex.self) 587 | } 588 | } 589 | 590 | func test_blas_scal() { 591 | func generic(_ type : E.Type) { 592 | var v : Vector = randomWholeVector() 593 | let alpha : E = randomWhole() 594 | let result = scale(alpha, v) 595 | E.blas_scal(Int32(v.count), alpha, &v, 1) 596 | XCTAssertEqual(v, result) 597 | } 598 | stress { 599 | generic(Float.self) 600 | generic(Double.self) 601 | generic(Complex.self) 602 | generic(Complex.self) 603 | } 604 | } 605 | 606 | func testEigen() { 607 | func generic(_ type : E.Type) { 608 | let n = Int.random(in: 0 ... 10) 609 | var A : Matrix = randomWholeMatrix(rows: n, columns: n) 610 | A = 0.5 * (A + A′) 611 | let eigen = A.eigen()! 612 | let D = Matrix(diagonal: eigen.eigenValues.map{ x in E(magnitude: x) }) 613 | let B = eigen.eigenVectors 614 | XCTSame(B ′* B, .eye(n)) 615 | XCTSame(B * D *′ B, A) 616 | } 617 | stress { 618 | generic(Float.self) 619 | generic(Double.self) 620 | generic(Complex.self) 621 | generic(Complex.self) 622 | } 623 | } 624 | 625 | func testSchur() { 626 | func generic(_ type : E.Type) where E.Magnitude : Real { 627 | let n = Int.random(in: 0 ... 10) 628 | let A : Matrix = randomWholeMatrix(rows: n, columns: n) 629 | let schur = A.schur()! 630 | let D = schur.schurForm 631 | let B = schur.schurVectors 632 | XCTSame(B ′* B, .eye(n)) 633 | XCTSame(B * D *′ B, A) 634 | if E.Magnitude.self == E.self { 635 | XCTAssert(D.isQuasiUpperTriangle) 636 | } else { 637 | XCTAssert(D.isUpperTriangle) 638 | } 639 | } 640 | stress { 641 | generic(Float.self) 642 | generic(Double.self) 643 | generic(Complex.self) 644 | generic(Complex.self) 645 | } 646 | } 647 | 648 | func test_vDSP_convert() { 649 | func generic(_ type : R.Type) { 650 | let v : Vector> = randomWholeVector() 651 | let real = v.map { x in x.real } 652 | let imaginary = v.map { x in x.imaginary } 653 | let split = Complex.vDSP_convert(interleavedComplex: v) 654 | XCTAssertEqual(real, split.real) 655 | XCTAssertEqual(imaginary, split.imaginary) 656 | let u = Complex.vDSP_convert(real: real, imaginary: imaginary) 657 | XCTAssertEqual(u, v) 658 | } 659 | stress { 660 | generic(Float.self) 661 | generic(Double.self) 662 | } 663 | } 664 | 665 | func test_vDSP_elementwise_absolute() { 666 | func generic(_ type : E.Type) { 667 | let v : [E] = randomWholeVector() 668 | let abs = E.vDSP_elementwise_absolute(v) 669 | let vabs = v.map { x in x.length } 670 | XCTSame(abs, vabs) 671 | } 672 | stress { 673 | generic(Float.self) 674 | generic(Double.self) 675 | generic(Complex.self) 676 | generic(Complex.self) 677 | } 678 | } 679 | 680 | func test_vDSP_elementwise_adjoint() { 681 | func generic(_ type : E.Type) { 682 | let v : [E] = randomWholeVector() 683 | let abs = E.vDSP_elementwise_adjoint(v) 684 | let vabs = v.map { x in x.adjoint } 685 | XCTSame(abs, vabs) 686 | } 687 | stress { 688 | generic(Float.self) 689 | generic(Double.self) 690 | generic(Complex.self) 691 | generic(Complex.self) 692 | } 693 | } 694 | 695 | func test_vDSP_elementwise_multiply() { 696 | func generic(_ type : E.Type) { 697 | let u : [E] = randomWholeVector() 698 | let v : [E] = randomWholeVector(count: u.count) 699 | let result = E.vDSP_elementwise_multiply(u, v) 700 | let predicted = zip(u, v).map { x, y in x * y } 701 | XCTSame(result, predicted) 702 | } 703 | stress { 704 | generic(Float.self) 705 | generic(Double.self) 706 | generic(Complex.self) 707 | generic(Complex.self) 708 | } 709 | } 710 | 711 | func test_vDSP_elementwise_divide() { 712 | func generic(_ type : E.Type) { 713 | let u : [E] = randomWholeVector() 714 | let v : [E] = randomWholeVector(count: u.count).map { x in x == 0 ? 1 : x } 715 | let result = E.vDSP_elementwise_divide(u, v) 716 | let predicted = zip(u, v).map { x, y in x / y } 717 | XCTSame(result, predicted) 718 | } 719 | stress { 720 | generic(Float.self) 721 | generic(Double.self) 722 | generic(Complex.self) 723 | generic(Complex.self) 724 | } 725 | } 726 | 727 | func test_vDSP_elementwise_operators() { 728 | func generic(_ type : E.Type) { 729 | let u : [E] = randomWholeVector() 730 | let v : [E] = randomWholeVector(count: u.count).map { x in x == 0 ? 1 : x } 731 | let u_plus_v = zip(u, v).map { x, y in x + y } 732 | XCTAssertEqual(u .+ v, u_plus_v) 733 | XCTAssertEqual(Matrix(u) .+ Matrix(v), Matrix(u_plus_v)) 734 | let u_minus_v = zip(u, v).map { x, y in x - y } 735 | XCTAssertEqual(u .- v, u_minus_v) 736 | XCTAssertEqual(Matrix(u) .- Matrix(v), Matrix(u_minus_v)) 737 | let u_times_v = zip(u, v).map { x, y in x * y } 738 | XCTAssertEqual(u .* v, u_times_v) 739 | XCTAssertEqual(Matrix(u) .* Matrix(v), Matrix(u_times_v)) 740 | let u_div_v = zip(u, v).map { x, y in x / y } 741 | XCTSame(u ./ v, u_div_v) 742 | XCTSame(Matrix(u) ./ Matrix(v), Matrix(u_div_v)) 743 | } 744 | stress { 745 | generic(Float.self) 746 | generic(Double.self) 747 | generic(Complex.self) 748 | generic(Complex.self) 749 | } 750 | } 751 | 752 | } 753 | --------------------------------------------------------------------------------