Skip to content

Commit 34a7550

Browse files
committed
Merge branch 'main' into quaternion/sync
# Conflicts: # Package.swift # README.md # Sources/Numerics/Numerics.swift
2 parents 65cf88a + f956c23 commit 34a7550

37 files changed

+2093
-233
lines changed

.github/workflows/macos.yml

Lines changed: 0 additions & 15 deletions
This file was deleted.

.xcodesamplecode.plist

Lines changed: 0 additions & 5 deletions
This file was deleted.

Package.swift

Lines changed: 84 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
import PackageDescription
1414

15+
let excludedFilenames = ["CMakeLists.txt", "README.md"]
16+
1517
let package = Package(
1618

1719
name: "swift-numerics",
@@ -23,23 +25,87 @@ let package = Package(
2325
],
2426

2527
targets: [
26-
// User-facing modules
27-
.target(name: "ComplexModule", dependencies: ["RealModule"]),
28-
.target(name: "Numerics", dependencies: ["ComplexModule", "QuaternionModule", "RealModule"]),
29-
.target(name: "QuaternionModule", dependencies: ["RealModule"]),
30-
.target(name: "RealModule", dependencies: ["_NumericsShims"]),
31-
32-
// Implementation details
33-
.target(name: "_NumericsShims", dependencies: []),
34-
.target(name: "_TestSupport", dependencies: ["Numerics"]),
35-
36-
// Unit test bundles
37-
.testTarget(name: "ComplexTests", dependencies: ["_TestSupport"]),
38-
.testTarget(name: "QuaternionTests", dependencies: ["_TestSupport"]),
39-
.testTarget(name: "RealTests", dependencies: ["_TestSupport"]),
40-
41-
// Test executables
42-
.target(name: "ComplexLog", dependencies: ["Numerics", "_TestSupport"], path: "Tests/Executable/ComplexLog"),
43-
.target(name: "ComplexLog1p", dependencies: ["Numerics", "_TestSupport"], path: "Tests/Executable/ComplexLog1p")
28+
// MARK: - Public API
29+
.target(
30+
name: "ComplexModule",
31+
dependencies: ["RealModule"],
32+
exclude: excludedFilenames
33+
),
34+
35+
.target(
36+
name: "IntegerUtilities",
37+
dependencies: [],
38+
exclude: excludedFilenames
39+
),
40+
41+
.target(
42+
name: "Numerics",
43+
dependencies: [
44+
"ComplexModule", "IntegerUtilities",
45+
"QuaternionModule", "RealModule"
46+
],
47+
exclude: excludedFilenames
48+
),
49+
50+
.target(
51+
name: "QuaternionModule",
52+
dependencies: ["RealModule"]
53+
),
54+
55+
.target(
56+
name: "RealModule",
57+
dependencies: ["_NumericsShims"],
58+
exclude: excludedFilenames
59+
),
60+
61+
// MARK: - Implementation details
62+
.target(
63+
name: "_NumericsShims",
64+
dependencies: [],
65+
exclude: excludedFilenames
66+
),
67+
68+
.target(
69+
name: "_TestSupport",
70+
dependencies: ["Numerics"],
71+
exclude: ["CMakeLists.txt"]
72+
),
73+
74+
// MARK: - Unit test bundles
75+
.testTarget(
76+
name: "ComplexTests",
77+
dependencies: ["_TestSupport"],
78+
exclude: ["CMakeLists.txt"]
79+
),
80+
81+
.testTarget(
82+
name: "IntegerUtilitiesTests",
83+
dependencies: ["IntegerUtilities"],
84+
exclude: ["CMakeLists.txt"]
85+
),
86+
87+
.testTarget(
88+
name: "QuaternionTests",
89+
dependencies: ["_TestSupport"]
90+
),
91+
92+
.testTarget(
93+
name: "RealTests",
94+
dependencies: ["_TestSupport"],
95+
exclude: ["CMakeLists.txt"]
96+
),
97+
98+
// MARK: - Test executables
99+
.target(
100+
name: "ComplexLog",
101+
dependencies: ["Numerics", "_TestSupport"],
102+
path: "Tests/Executable/ComplexLog"
103+
),
104+
105+
.target(
106+
name: "ComplexLog1p",
107+
dependencies: ["Numerics", "_TestSupport"],
108+
path: "Tests/Executable/ComplexLog1p"
109+
)
44110
]
45111
)

README.md

Lines changed: 43 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ These modules fall broadly into two categories:
1111
There is some overlap between these two categories, and an API that begins in the first category may migrate into the second as it matures and new uses are discovered.
1212

1313
Swift Numerics modules are fine-grained.
14-
For example, if you need support for Complex numbers, you can import ComplexModule¹ as a standalone module:
14+
For example, if you need support for Complex numbers, you can import ComplexModule[^1] as a standalone module:
1515

1616
```swift
1717
import ComplexModule
@@ -42,7 +42,7 @@ To use Swift Numerics in a SwiftPM project:
4242
1. Add the following line to the dependencies in your `Package.swift` file:
4343

4444
```swift
45-
.package(url: "https://github.com/apple/swift-numerics", from: "0.0.7"),
45+
.package(url: "https://github.com/apple/swift-numerics", from: "1.0.0"),
4646
```
4747

4848
2. Add `Numerics` as a dependency for your target:
@@ -56,6 +56,22 @@ To use Swift Numerics in a SwiftPM project:
5656

5757
3. Add `import Numerics` in your source code.
5858

59+
## Source stability
60+
61+
The Swift Numerics package is source stable; version numbers follow [Semantic Versioning](https://semver.org).
62+
The public API of the `swift-numerics` package consists of non-underscored declarations that are marked either `public` or `usableFromInline` in modules re-exported by the top-level `Numerics` module, *excepting any API that involves a conformance to Differentiable (because Differentiable itself is not stable in Swift)*.
63+
Interfaces that aren't part of the public API may continue to change in any release, including patch releases.
64+
65+
Note that contents of the `_NumericsShims` and `_TestSupport` modules, as well as contents of the `Tests` directory, explicitly are not public API.
66+
The definitions therein may therefore change at whim, and the entire module may be removed in any new release.
67+
If you have a use case that requires underscored operations, please raise an issue to request that they be made public API.
68+
69+
Future minor versions of the package may introduce changes to these rules as needed.
70+
71+
We'd like this package to quickly embrace Swift language and toolchain improvements that are relevant to its mandate.
72+
Accordingly, from time to time, we expect that new versions of this package will require clients to upgrade to a more recent Swift toolchain release.
73+
Requiring a new Swift release will only require a minor version bump.
74+
5975
## Contributing to Swift Numerics
6076

6177
Swift Numerics is a standalone library that is separate from the core Swift project, but it will sometimes act as a staging ground for APIs that will later be incorporated into the Swift Standard Library.
@@ -89,7 +105,8 @@ Questions about how to use Swift Numerics modules, or issues that are not clearl
89105

90106
1. [`RealModule`](Sources/RealModule/README.md)
91107
2. [`ComplexModule`](Sources/ComplexModule/README.md)
92-
3. [`QuaternionModule`](Sources/QuaternionModule/README.md)
108+
3. [`IntegerUtilities`](Sources/IntegerUtilties/README.md) (on main only, not yet present in a released tag)
109+
4. [`QuaternionModule`](Sources/QuaternionModule/README.md)
93110

94111
## Future expansion
95112

@@ -98,28 +115,26 @@ Questions about how to use Swift Numerics modules, or issues that are not clearl
98115
3. [Shaped Arrays](https://github.com/apple/swift-numerics/issues/6)
99116
4. [Decimal Floating-point](https://github.com/apple/swift-numerics/issues/7)
100117

101-
## Notes
102-
103-
¹ Swift is currently unable to use the fully-qualified name for types when a type and module have the same name (discussion here: https://forums.swift.org/t/pitch-fully-qualified-name-syntax/28482).
104-
This would prevent users of Swift Numerics who don't need generic types from doing things such as:
105-
106-
```swift
107-
import Complex
108-
// I know I only ever want Complex<Double>, so I shouldn't need the generic parameter.
109-
typealias Complex = Complex.Complex<Double> // This doesn't work, because name lookup fails.
110-
```
111-
112-
For this reason, modules that would have this ambiguity are suffixed with `Module` within Swift Numerics:
113-
114-
```swift
115-
import ComplexModule
116-
// I know I only ever want Complex<Double>, so I shouldn't need the generic parameter.
117-
typealias Complex = ComplexModule.Complex<Double>
118-
// But I can still refer to the generic type by qualifying the name if I need it occasionally:
119-
let a = ComplexModule.Complex<Float>
120-
```
121-
122-
The `Real` module does not contain a `Real` type, but does contain a `Real` protocol.
123-
Users may want to define their own `Real` type (and possibly re-export the `Real` module)--that is why the suffix is also applied there.
124-
New modules have to evaluate this decision carefully, but can err on the side of adding the suffix.
125-
It's expected that most users will simply `import Numerics`, so this isn't an issue for them.
118+
[^1]: The module is named `ComplexModule` instead of `Complex` because Swift is currently unable to use the fully-qualified name for types when a type and module have the same name (discussion here: https://forums.swift.org/t/pitch-fully-qualified-name-syntax/28482).
119+
This would prevent users of Swift Numerics who don't need generic types from doing things such as:
120+
121+
```swift
122+
import Complex
123+
// I know I only ever want Complex<Double>, so I shouldn't need the generic parameter.
124+
typealias Complex = Complex.Complex<Double> // This doesn't work, because name lookup fails.
125+
```
126+
127+
For this reason, modules that would have this ambiguity are suffixed with `Module` within Swift Numerics:
128+
129+
```swift
130+
import ComplexModule
131+
// I know I only ever want Complex<Double>, so I shouldn't need the generic parameter.
132+
typealias Complex = ComplexModule.Complex<Double>
133+
// But I can still refer to the generic type by qualifying the name if I need it occasionally:
134+
let a = ComplexModule.Complex<Float>
135+
```
136+
137+
The `Real` module does not contain a `Real` type, but does contain a `Real` protocol.
138+
Users may want to define their own `Real` type (and possibly re-export the `Real` module)--that is why the suffix is also applied there.
139+
New modules have to evaluate this decision carefully, but can err on the side of adding the suffix.
140+
It's expected that most users will simply `import Numerics`, so this isn't an issue for them.

Sources/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
#[[
22
This source file is part of the Swift Numerics open source project
33
4-
Copyright (c) 2019 Apple Inc. and the Swift Numerics project authors
4+
Copyright (c) 2019-2021 Apple Inc. and the Swift Numerics project authors
55
Licensed under Apache License v2.0 with Runtime Library Exception
66
77
See https://swift.org/LICENSE.txt for license information
88
#]]
99

1010
add_subdirectory(_NumericsShims)
1111
add_subdirectory(ComplexModule)
12+
add_subdirectory(IntegerUtilities)
1213
add_subdirectory(Numerics)
1314
add_subdirectory(RealModule)
1415
if(BUILD_TESTING)

Sources/ComplexModule/Arithmetic.swift

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,31 @@ extension Complex: AdditiveArithmetic {
5252
// and turn these into operators if/when we have it.
5353
// (https://github.com/apple/swift-numerics/issues/12)
5454
extension Complex {
55+
/// `self` scaled by `a`.
5556
@usableFromInline @_transparent
5657
internal func multiplied(by a: RealType) -> Complex {
58+
// This can be viewed in two different ways, which are mathematically
59+
// equivalent: either we are computing `self * Complex(a)` (i.e.
60+
// converting `a` to be a complex value, and then using the complex
61+
// multiplication) or we are using the scalar product of the vector
62+
// space structure: `Complex(a*real, a*imaginary)`.
63+
//
64+
// Although these two interpretations are _mathematically_ equivalent,
65+
// they will generate different representations of the point at
66+
// infinity in general. For example, suppose `self` is represented by
67+
// `(infinity, 0)`. Then `self * Complex(1)` would evaluate as
68+
// `(1*infinity - 0*0, 0*infinity + 1*0) = (infinity, nan)`, but
69+
// the vector space interpretation produces `(infinity, 0)`. This does
70+
// not matter much, because these are two representations of the same
71+
// semantic value, but note that one requires four multiplies and two
72+
// additions, while the one we use requires only two real multiplications.
5773
Complex(x*a, y*a)
5874
}
5975

76+
/// `self` unscaled by `a`.
6077
@usableFromInline @_transparent
6178
internal func divided(by a: RealType) -> Complex {
79+
// See implementation notes for `multiplied` above.
6280
Complex(x/a, y/a)
6381
}
6482
}
@@ -126,8 +144,8 @@ extension Complex: AlgebraicField {
126144

127145
/// A normalized complex number with the same phase as this value.
128146
///
129-
/// If such a value cannot be produced (because the phase of zero and infinity is undefined),
130-
/// `nil` is returned.
147+
/// If such a value cannot be produced (because the phase of zero and
148+
/// infinity is undefined), `nil` is returned.
131149
@inlinable
132150
public var normalized: Complex? {
133151
if length.isNormal {
@@ -139,23 +157,31 @@ extension Complex: AlgebraicField {
139157
return self.divided(by: magnitude).normalized
140158
}
141159

142-
/// The reciprocal of this value, if it can be computed without undue overflow or underflow.
160+
/// The reciprocal of this value, if it can be computed without undue
161+
/// overflow or underflow.
143162
///
144-
/// If z.reciprocal is non-nil, you can safely replace division by z with multiplication by this value. It is
145-
/// not advantageous to do this for an isolated division, but if you are dividing many values by a single
163+
/// If z.reciprocal is non-nil, you can safely replace division by z with
164+
/// multiplication by this value. It is not advantageous to do this for an
165+
/// isolated division, but if you are dividing many values by a single
146166
/// denominator, this will often be a significant performance win.
147167
///
148-
/// Typical use looks like this:
168+
/// A typical use case looks something like this:
149169
/// ```
150170
/// func divide<T: Real>(data: [Complex<T>], by divisor: Complex<T>) -> [Complex<T>] {
151-
/// // If divisor is well-scaled, use multiply by reciprocal.
171+
/// // If divisor is well-scaled, multiply by reciprocal.
152172
/// if let recip = divisor.reciprocal {
153173
/// return data.map { $0 * recip }
154174
/// }
155175
/// // Fallback on using division.
156176
/// return data.map { $0 / divisor }
157177
/// }
158178
/// ```
179+
///
180+
/// Error Bounds:
181+
/// -
182+
/// Unlike real types, when working with complex types, multiplying by the
183+
/// reciprocal instead of dividing cannot change the result. If the
184+
/// reciprocal is non-nil, the two computations are always equivalent.
159185
@inlinable
160186
public var reciprocal: Complex? {
161187
let recip = 1/self

0 commit comments

Comments
 (0)