├── .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 
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