├── .gitignore ├── Cartfile ├── Cartfile.private ├── Cartfile.resolved ├── Carthage └── Checkouts │ └── Set │ ├── .gitignore │ ├── .travis.yml │ ├── LICENSE │ ├── README.md │ ├── Set.podspec │ ├── Set.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ ├── Set-Mac.xcscheme │ │ └── Set-iOS.xcscheme │ ├── Set │ ├── Hashing.swift │ ├── Info.plist │ ├── Multiset.swift │ ├── PredicateSet.swift │ ├── Printing.swift │ └── Set.h │ └── SetTests │ ├── Info.plist │ ├── MultisetAlgebraTests.swift │ ├── MultisetCollectionTests.swift │ ├── MultisetCountTests.swift │ ├── MultisetHigherOrderFunctionTests.swift │ ├── MultisetInclusionTests.swift │ ├── MultisetInitializerTests.swift │ ├── MultisetPrintableTests.swift │ ├── MultisetSequenceTests.swift │ └── PredicateSetTests.swift ├── Examples.playground └── Sources │ └── Benchmarker.swift ├── LICENSE ├── Playground.playground ├── Contents.swift ├── Sources │ └── Benchmarker.swift ├── contents.xcplayground ├── playground.xcworkspace │ └── contents.xcworkspacedata └── timeline.xctimeline ├── README.md ├── SwiftMath.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ ├── SwiftMath-Mac.xcscheme │ └── SwiftMath-iOS.xcscheme ├── SwiftMath.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ └── SwiftMath.xcscmblueprint ├── SwiftMath ├── Benchmarker.swift ├── Complex.swift ├── Expression.swift ├── Info.plist ├── MatrixType.swift ├── Memoize.swift ├── Polynomial.swift ├── Quaternion.swift ├── RealType.swift ├── SquareMatrix.swift ├── SquareMatrixType.swift ├── Surge │ ├── Arithmetic.swift │ ├── Auxiliary.swift │ ├── Exponential.swift │ ├── FFT.swift │ ├── Hyperbolic.swift │ ├── Matrix.swift │ ├── Power.swift │ ├── RealTypeAnalysis.swift │ ├── RealTypeArrayExtension.swift │ └── Trigonometric.swift ├── SwiftMath.h ├── Vector.swift ├── Vector2.swift ├── Vector3.swift └── VectorType.swift └── SwiftMathTests ├── ComplexMultisetMatcher.swift ├── ComplexTests.swift ├── Info.plist ├── PolynomialTests.swift ├── QuaternionTests.swift ├── Surge ├── ArithmeticTests.swift ├── AuxiliaryTests.swift ├── ExponentialTests.swift ├── HyperbolicTests.swift ├── TrigonometricTests.swift └── XCTestCase+Surge.swift ├── Vector3Matcher.swift └── Vector3Tests.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | # Pods/ 27 | 28 | # Carthage 29 | # 30 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 31 | # Carthage/Checkouts 32 | 33 | Carthage/Build -------------------------------------------------------------------------------- /Cartfile: -------------------------------------------------------------------------------- 1 | github "robrix/Set" "master" 2 | -------------------------------------------------------------------------------- /Cartfile.private: -------------------------------------------------------------------------------- 1 | github "Quick/Quick" 2 | github "Quick/Nimble" 3 | -------------------------------------------------------------------------------- /Cartfile.resolved: -------------------------------------------------------------------------------- 1 | github "Quick/Nimble" "v3.0.0" 2 | github "Quick/Quick" "v0.8.0" 3 | github "robrix/Set" "c3f6d5aa764ae902a6c8055aded0c131eda3f67e" 4 | -------------------------------------------------------------------------------- /Carthage/Checkouts/Set/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | build 3 | xcuserdata 4 | *.mode* 5 | *.pbxuser 6 | *.xcuserdatad 7 | *.xccheckout 8 | -------------------------------------------------------------------------------- /Carthage/Checkouts/Set/.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | osx_image: beta-xcode6.3 3 | script: 4 | - xctool -project Set.xcodeproj -scheme Set-Mac build test 5 | - xctool -project Set.xcodeproj -scheme Set-iOS -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO build test 6 | notifications: 7 | email: false 8 | -------------------------------------------------------------------------------- /Carthage/Checkouts/Set/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Rob Rix 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. -------------------------------------------------------------------------------- /Carthage/Checkouts/Set/README.md: -------------------------------------------------------------------------------- 1 | # Set 2 | 3 | [![Build status](https://api.travis-ci.org/robrix/Set.svg)](https://travis-ci.org/robrix/Set) 4 | 5 | This is a Swift microframework which implements a PredicateSet and a Dictionary-backed Multiset. 6 | 7 | ## Use 8 | Multiset: 9 | ```swift 10 | // Union 11 | Multiset(1, 2, 3) + Multiset(3, 4, 5) // == Multiset(1, 2, 3, 3, 4, 5) 12 | 13 | // Difference 14 | Multiset(1, 2, 3) - Multiset(2, 3) // == Multiset(1) 15 | 16 | // Intersection 17 | Multiset(1, 2, 3) & Multiset(3, 4, 5) // == Multiset(3) 18 | ``` 19 | PredicateSet: 20 | ```swift 21 | // Union 22 | let union = PredicateSet { $0 > 0 } + PredicateSet { $0 % 2 == 0 } 23 | union.contains(3) // true 24 | 25 | // Difference 26 | let difference = PredicateSet { $0 > 0 } - PredicateSet { $0 % 2 == 0 } 27 | difference.contains(6) // false 28 | 29 | // Special Sets 30 | func isInt(number: Float) -> Bool { 31 | return Float(Int(number)) == number 32 | } 33 | 34 | let Q: PredicateSet = PredicateSet { _ in true } // Set of all real numbers. 35 | let Z = Q & PredicateSet { isInt($0) } // Set of all integers. 36 | let N = Z & PredicateSet { $0 > 0 } // Set of all natural numbers. 37 | 38 | N.contains(1) // true 39 | N.contains(-1.5) // false 40 | ``` 41 | See [`Multiset.swift`][Multiset.swift] and [`PredicateSet.swift`][PredicateSet.swift] for more details. 42 | 43 | ## Integration 44 | 45 | 1. Add this repo as a submodule in e.g. `External/Set`: 46 | 47 | git submodule add https://github.com/robrix/Set.git External/Set 48 | 2. Drag `Set.xcodeproj` into your `.xcworkspace`/`.xcodeproj`. 49 | 3. Add `Set.framework` to your target’s `Link Binary With Libraries` build phase. 50 | 4. You may also want to add a `Copy Files` phase which copies `Set.framework` (and any other framework dependencies you need) into your bundle’s `Frameworks` directory. If your target is a framework, you may instead want the client app to include `Set.framework`. 51 | 52 | ## Thanks 53 | 54 | - [Greg Titus wrote a Set in Swift which inspired this](https://twitter.com/gregtitus/status/476420154230726656). 55 | - The Swift team at Apple added a `Set` type to the standard library in Swift 1.2, which reduced our support load considerably. 56 | 57 | [Multiset.swift]: https://github.com/robrix/Set/blob/master/Set/Multiset.swift 58 | [PredicateSet.swift]: https://github.com/robrix/Set/blob/master/Set/PredicateSet.swift 59 | -------------------------------------------------------------------------------- /Carthage/Checkouts/Set/Set.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "Set" 3 | s.version = "1.2" 4 | s.summary = "An implementation of a Dictionary-backed Set in Swift." 5 | s.homepage = "https://github.com/robrix/Set" 6 | s.authors = { "Rob Rix" => "rob.rix@github.com", "Adam Sharp" => "adsharp@me.com", "Ingmar Stein" => "IngmarStein@gmail.com" } 7 | s.source = { :git => "https://github.com/robrix/Set.git", :tag => "1.2" } 8 | s.ios.deployment_target = "7.0" 9 | s.osx.deployment_target = "10.9" 10 | s.source_files = "Set/*.swift" 11 | s.requires_arc = true 12 | s.license = { :type => "MIT", :file => "LICENSE" } 13 | s.description = <<-DESC 14 | This is a Swift microframework which implements a Dictionary-backed Set. 15 | DESC 16 | end 17 | -------------------------------------------------------------------------------- /Carthage/Checkouts/Set/Set.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Carthage/Checkouts/Set/Set.xcodeproj/xcshareddata/xcschemes/Set-Mac.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 78 | 79 | 85 | 86 | 87 | 88 | 89 | 90 | 96 | 97 | 103 | 104 | 105 | 106 | 108 | 109 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /Carthage/Checkouts/Set/Set.xcodeproj/xcshareddata/xcschemes/Set-iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 78 | 79 | 85 | 86 | 87 | 88 | 89 | 90 | 96 | 97 | 103 | 104 | 105 | 106 | 108 | 109 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /Carthage/Checkouts/Set/Set/Hashing.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Rob Rix. All rights reserved. 2 | 3 | /// Hashes a sequence of `Hashable` elements. 4 | internal func hashValues(sequence: S) -> Int { 5 | var h = sequence.reduce(0) { into, each in 6 | var h = into + each.hashValue 7 | h += (h << 10) 8 | h ^= (h >> 6) 9 | return h 10 | } 11 | h += (h << 3) 12 | h ^= (h >> 11) 13 | h += (h << 15) 14 | return h 15 | } 16 | -------------------------------------------------------------------------------- /Carthage/Checkouts/Set/Set/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.4.1 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSHumanReadableCopyright 24 | Copyright © 2014 Rob Rix. All rights reserved. 25 | NSPrincipalClass 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Carthage/Checkouts/Set/Set/Multiset.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Rob Rix. All rights reserved. 2 | 3 | /// A multiset of elements and their counts. 4 | public struct Multiset: ArrayLiteralConvertible, Hashable, CustomStringConvertible, CustomDebugStringConvertible, CollectionType { 5 | // MARK: Constructors 6 | 7 | /// Constructs a `Multiset` with the elements of `sequence`. 8 | public init(_ sequence: S) { 9 | self.init(values: [:]) 10 | extend(sequence) 11 | } 12 | 13 | /// Constructs a `Multiset` from a variadic parameter list. 14 | public init(_ elements: Element...) { 15 | self.init(elements) 16 | } 17 | 18 | /// Constructs the empty `Multiset`. 19 | public init() { 20 | self.init(values: [:]) 21 | } 22 | 23 | /// Constructs an empty `Multiset` with a hint as to the capacity it should allocate. 24 | public init(minimumCapacity: Int) { 25 | self.init(values: [Element: Int](minimumCapacity: minimumCapacity)) 26 | } 27 | 28 | 29 | // MARK: Properties 30 | 31 | /// The number of entries in the receiver. 32 | public var count: Int { 33 | return values.values.reduce(0, combine: +) 34 | } 35 | 36 | /// The number of distinct entries in the receiver. 37 | public var countDistinct: Int { 38 | return values.count 39 | } 40 | 41 | /// True iff `count` is 0. 42 | public var isEmpty: Bool { 43 | return values.isEmpty 44 | } 45 | 46 | 47 | // MARK: Primitive operations 48 | 49 | /// True iff `element` is in the receiver, as defined by its hash and equality. 50 | public func contains(element: Element) -> Bool { 51 | return count(element) > 0 52 | } 53 | 54 | /// Returns the number of occurrences of `element` in the receiver. 55 | public func count(element: Element) -> Int { 56 | return values[element] ?? 0 57 | } 58 | 59 | /// Inserts `element` into the receiver. 60 | public mutating func insert(element: Element) { 61 | values[element] = (values[element] ?? 0) + 1 62 | } 63 | 64 | /// Removes `element` from the receiver. 65 | public mutating func remove(element: Element) { 66 | if let value = values[element] where value > 1 { 67 | values[element] = value - 1 68 | } else { 69 | values.removeValueForKey(element) 70 | } 71 | } 72 | 73 | /// Removes all elements from the receiver, optionally maintaining its capacity (defaulting to false). 74 | public mutating func removeAll(keepCapacity: Bool = false) { 75 | values.removeAll(keepCapacity: keepCapacity) 76 | } 77 | 78 | 79 | // MARK: Algebraic operations 80 | 81 | /// Returns the union of the receiver and `set`. 82 | public func union(set: Multiset) -> Multiset { 83 | return self + set 84 | } 85 | 86 | /// Returns the intersection of the receiver and `set`. 87 | public func intersection(set: Multiset) -> Multiset { 88 | return Multiset(values: countDistinct <= set.countDistinct ? 89 | values.map { ($0, min($1, set.count($0))) } 90 | : set.values.map { ($0, min($1, self.count($0))) }) 91 | } 92 | 93 | /// Returns the relative complement of `set` in `self`. 94 | /// 95 | /// This is a new set with all elements from the receiver which are not contained in `set`. 96 | public func complement(set: Multiset) -> Multiset { 97 | return Multiset(values: values.lazy.map { ($0, $1 - set.count($0)) }) 98 | } 99 | 100 | /// Returns the symmetric difference of `self` and `set`. 101 | /// 102 | /// This is a new set with all elements that exist only in `self` or `set`, and not both. 103 | public func difference(set: Multiset) -> Multiset { 104 | return (set - self) + (self - set) 105 | } 106 | 107 | 108 | // MARK: Inclusion functions 109 | 110 | /// True iff the receiver is a subset of (is included in) `set`. 111 | public func subset(set: Multiset) -> Bool { 112 | return complement(set) == Multiset() 113 | } 114 | 115 | /// True iff the receiver is a subset of but not equal to `set`. 116 | public func strictSubset(set: Multiset) -> Bool { 117 | return subset(set) && self != set 118 | } 119 | 120 | /// True iff the receiver is a superset of (includes) `set`. 121 | public func superset(set: Multiset) -> Bool { 122 | return set.subset(self) 123 | } 124 | 125 | /// True iff the receiver is a superset of but not equal to `set`. 126 | public func strictSuperset(set: Multiset) -> Bool { 127 | return set.strictSubset(self) 128 | } 129 | 130 | 131 | // MARK: Higher-order functions 132 | 133 | /// Returns a new set including only those elements `x` where `includeElement(x)` is true. 134 | public func filter(includeElement: Element -> Bool) -> Multiset { 135 | return Multiset(self.lazy.filter(includeElement)) 136 | } 137 | 138 | /// Returns a new set with the result of applying `transform` to each element. 139 | public func map(transform: Element -> Result) -> Multiset { 140 | return flatMap { [transform($0)] } 141 | } 142 | 143 | /// Applies `transform` to each element and returns a new set which is the union of each resulting set. 144 | public func flatMap(transform: Element -> S) -> Multiset { 145 | return reduce([]) { $0 + transform($1) } 146 | } 147 | 148 | /// Combines each element of the receiver with an accumulator value using `combine`, starting with `initial`. 149 | public func reduce(initial: Into, _ combine: (Into, Element) -> Into) -> Into { 150 | return reduce(initial, combine: combine) 151 | } 152 | 153 | 154 | // MARK: ArrayLiteralConvertible 155 | 156 | public init(arrayLiteral elements: Element...) { 157 | self.init(elements) 158 | } 159 | 160 | 161 | // MARK: SequenceType 162 | 163 | public typealias Generator = AnyGenerator 164 | 165 | public func generate() -> Generator { 166 | var generator = values.generate() 167 | let next = { generator.next() } 168 | var current: (element: Element?, count: Int) = (nil, 0) 169 | return anyGenerator { 170 | while current.count <= 0 { 171 | if let (element, count) = next() { 172 | current = (element, count) 173 | break 174 | } 175 | else { return nil } 176 | } 177 | --current.count 178 | return current.element 179 | } 180 | } 181 | 182 | 183 | // MARK: CollectionType 184 | 185 | public typealias Index = MultisetIndex 186 | 187 | public var startIndex: Index { 188 | return MultisetIndex(from: values.startIndex, delta: 0, max: count) 189 | } 190 | 191 | public var endIndex: Index { 192 | return MultisetIndex(from: values.endIndex, delta: 0, max: count) 193 | } 194 | 195 | public subscript(index: Index) -> Element { 196 | let (element, count) = values[index.from] 197 | if index.delta > (count - 1) { 198 | return self[MultisetIndex(from: index.from.successor(), delta: index.delta - count, max: self.count)] 199 | } else { 200 | return element 201 | } 202 | } 203 | 204 | 205 | // MARK: ExtensibleCollectionType 206 | 207 | /// In theory, reserve capacity for `n` elements. However, `Dictionary` does not implement `reserveCapacity`, so we just silently ignore it. 208 | public func reserveCapacity(n: Multiset.Index.Distance) {} 209 | 210 | /// Inserts each element of `sequence` into the receiver. 211 | public mutating func extend(sequence: S) { 212 | // Note that this should just be for each in sequence; this is working around a compiler bug. 213 | for each in AnySequence(sequence) { 214 | insert(each) 215 | } 216 | } 217 | 218 | /// Appends `element` onto the `Multiset`. 219 | public mutating func append(element: Element) { 220 | insert(element) 221 | } 222 | 223 | 224 | // MARK: Hashable 225 | 226 | /// Hashes using Bob Jenkins’ one-at-a-time hash. 227 | /// 228 | /// http://en.wikipedia.org/wiki/Jenkins_hash_function#one-at-a-time 229 | /// 230 | /// NB: Jenkins’ usage appears to have been string keys; the usage employed here seems similar but may have subtle differences which have yet to be discovered. 231 | public var hashValue: Int { 232 | return hashValues(self) 233 | } 234 | 235 | 236 | // MARK: CustomStringConvertible 237 | 238 | public var description: String { 239 | return describe(self) 240 | } 241 | 242 | 243 | // MARK: CustomDebugStringConvertible 244 | 245 | public var debugDescription: String { 246 | return debugDescribe(self) 247 | } 248 | 249 | 250 | // MARK: Private 251 | 252 | /// Constructs a `Multiset` with a dictionary of `values`. 253 | private init(values: [Element: Int]) { 254 | self.values = values 255 | } 256 | 257 | /// Constructs a `Multiset` with a sequence of element/count pairs. 258 | private init.Element>(values: S) { 259 | self.values = [:] 260 | for (element, count) in values { 261 | if count > 0 { self.values[element] = count } 262 | } 263 | } 264 | 265 | /// Counts indexed by value. 266 | private var values: Dictionary 267 | } 268 | 269 | 270 | // MARK: - Operators 271 | 272 | /// Returns a new set with all elements from `set` and `other`. 273 | public func + (var set: Multiset, other: S) -> Multiset { 274 | for element in other { 275 | set.insert(element) 276 | } 277 | return set 278 | } 279 | 280 | /// Extends a `set` with the elements of a `sequence`. 281 | public func += (inout set: Multiset, sequence: S) { 282 | set.extend(sequence) 283 | } 284 | 285 | 286 | /// Returns a new set with all elements from `set` which are not contained in `other`. 287 | public func - (set: Multiset, other: Multiset) -> Multiset { 288 | return set.complement(other) 289 | } 290 | 291 | /// Removes all elements in `other` from `set`. 292 | public func -= (inout set: Multiset, other: Multiset) { 293 | set = set.complement(other) 294 | } 295 | 296 | 297 | /// Intersects with `set` with `other`. 298 | public func &= (inout set: Multiset, other: Multiset) { 299 | set = set.intersection(other) 300 | } 301 | 302 | /// Returns the intersection of `set` and `other`. 303 | public func & (set: Multiset, other: Multiset) -> Multiset { 304 | return set.intersection(other) 305 | } 306 | 307 | 308 | // Defines equality for multisets. 309 | public func == (a: Multiset, b: Multiset) -> Bool { 310 | return a.values == b.values 311 | } 312 | 313 | 314 | /// The index for values of a multiset. 315 | public struct MultisetIndex: ForwardIndexType, Comparable { 316 | // MARK: ForwardIndexType 317 | 318 | public func successor() -> MultisetIndex { 319 | return MultisetIndex(from: from, delta: delta + 1, max: max) 320 | } 321 | 322 | 323 | // MARK: Private 324 | 325 | private let from: DictionaryIndex 326 | private let delta: Int 327 | private let max: Int 328 | } 329 | 330 | 331 | // MARK: Equatable 332 | 333 | public func == (left: MultisetIndex, right: MultisetIndex) -> Bool { 334 | if left.from == right.from { 335 | return left.delta == right.delta && left.max == right.max 336 | } else { 337 | return left.max == right.max && abs(left.delta - right.delta) == left.max 338 | } 339 | } 340 | 341 | 342 | // MARK: Comparable 343 | 344 | public func < (left: MultisetIndex, right: MultisetIndex) -> Bool { 345 | if left.from == right.from { 346 | return left.delta < right.delta 347 | } else if left.from < right.from { 348 | return (left.delta - right.delta) < left.max 349 | } 350 | return false 351 | } 352 | 353 | 354 | -------------------------------------------------------------------------------- /Carthage/Checkouts/Set/Set/PredicateSet.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Rob Rix. All rights reserved. 2 | 3 | /// A set of elements of type T expressed mathematically as: 4 | /// { 𝑥 ∈ T | proposition(𝑥) }. 5 | public struct PredicateSet { 6 | // MARK: Constructors 7 | 8 | /// Constructs an empty `PredicateSet`. 9 | public init() { 10 | predicate = { _ in false } 11 | } 12 | 13 | /// Constructs a `PredicateSet` from a boolean predicate. 14 | public init(_ predicate: Element -> Bool) { 15 | self.predicate = predicate 16 | } 17 | 18 | /// Constructs a `PredicateSet` from a `Set`. 19 | public init(_ set: Set) { 20 | predicate = { set.contains($0) } 21 | } 22 | 23 | /// Constructs a `PredicateSet` from a `Multiset`. 24 | public init(_ set: Multiset) { 25 | predicate = { set.contains($0) } 26 | } 27 | 28 | 29 | // MARK: Properties 30 | 31 | /// The set's predicate. 32 | private let predicate: Element -> Bool 33 | 34 | 35 | // MARK: Primitive operations 36 | 37 | /// True iff predicate is true for `element`. (In other words, whether `element` is contained within the possibly infinite PredicateSet.) 38 | public func contains(element: Element) -> Bool { 39 | return predicate(element) 40 | } 41 | 42 | 43 | // MARK: Algebraic operations 44 | 45 | /// Returns the union of the receiver and `set`. 46 | public func union(set: PredicateSet) -> PredicateSet { 47 | return PredicateSet { self.predicate($0) || set.contains($0) } 48 | } 49 | 50 | /// Returns the intersection of the receiver and `set`. 51 | public func intersection(set: PredicateSet) -> PredicateSet { 52 | return PredicateSet { self.predicate($0) && set.contains($0) } 53 | } 54 | 55 | /// Returns the relative complement of the receiver and `set`. 56 | public func complement(set: PredicateSet) -> PredicateSet { 57 | return PredicateSet { self.predicate($0) && !set.contains($0) } 58 | } 59 | 60 | /// Returns the symmetric difference of the receiver and `set`. 61 | public func difference(set: PredicateSet) -> PredicateSet { 62 | return PredicateSet { !(self.predicate($0) && set.contains($0)) } 63 | } 64 | } 65 | 66 | 67 | // MARK: - Operators 68 | 69 | /// Returns the union of `lhs` and `rhs`. 70 | public func +(lhs: PredicateSet, rhs: PredicateSet) -> PredicateSet { 71 | return lhs.union(rhs) 72 | } 73 | 74 | /// Returns the symmetric difference of `lhs` and `rhs`. 75 | public func -(lhs: PredicateSet, rhs: PredicateSet) -> PredicateSet { 76 | return lhs.difference(rhs) 77 | } 78 | 79 | /// Returns the intersection of `lhs` and `rhs`. 80 | public func &(lhs: PredicateSet, rhs: PredicateSet) -> PredicateSet { 81 | return lhs.intersection(rhs) 82 | } 83 | -------------------------------------------------------------------------------- /Carthage/Checkouts/Set/Set/Printing.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Rob Rix. All rights reserved. 2 | 3 | /// Describes a sequence as a set. 4 | internal func describe(sequence: S) -> String { 5 | return mapDescription(sequence, transform: toString) 6 | } 7 | 8 | /// Debug-describes a sequence as a set. 9 | internal func debugDescribe(sequence: S) -> String { 10 | return mapDescription(sequence, transform: toDebugString) 11 | } 12 | 13 | /// Maps the elements of `sequence` with `transform` and formats them as a set. 14 | private func mapDescription(sequence: S, transform: S.Generator.Element -> String) -> String { 15 | return wrapDescription(sequence.lazy.map(transform).joinWithSeparator(", ")) 16 | } 17 | 18 | /// Wraps a string appropriately for formatting as a set. 19 | private func wrapDescription(description: String) -> String { 20 | return description.isEmpty ? 21 | "{}" 22 | : "{\(description)}" 23 | } 24 | 25 | // Returns the result of `print`ing x into a `String` 26 | private func toString(x: T) -> String { 27 | return String(x) 28 | } 29 | 30 | // Returns the result of `debugPrint`ing x into a `String` 31 | private func toDebugString(x: T) -> String { 32 | return String(reflecting: x) 33 | } 34 | -------------------------------------------------------------------------------- /Carthage/Checkouts/Set/Set/Set.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014 Rob Rix. All rights reserved. 2 | 3 | /// Project version number for Set. 4 | extern double SetVersionNumber; 5 | 6 | /// Project version string for Set. 7 | extern const unsigned char SetVersionString[]; 8 | -------------------------------------------------------------------------------- /Carthage/Checkouts/Set/SetTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Carthage/Checkouts/Set/SetTests/MultisetAlgebraTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Rob Rix. All rights reserved. 2 | 3 | import Set 4 | import XCTest 5 | 6 | final class MultisetAlgebraTests: XCTestCase { 7 | func testUnionOfMultisetsSumsMultiplicities() { 8 | XCTAssertEqual((Multiset(1, 2, 3) + Multiset(1)).count(1), 2) 9 | } 10 | 11 | func testIntersectionOfMultisetsMinimizesMultiplicities() { 12 | XCTAssertEqual((Multiset(1, 1, 1, 2, 3) & Multiset(1, 1, 2, 4)), Multiset(1, 1, 2)) 13 | } 14 | 15 | func testComplementOfMultisetsSubtractsMultiplicities() { 16 | XCTAssertEqual((Multiset(1, 1, 1, 2, 3) - Multiset(1, 1, 2, 4, 5)), Multiset(1, 3)) 17 | XCTAssertEqual((Multiset(1, 1, 2, 4, 5) - Multiset(1, 1, 1, 2, 3)), Multiset(4, 5)) 18 | } 19 | 20 | func testDifferenceOfMultisets() { 21 | XCTAssertEqual(Multiset(1, 1, 1, 2, 3).difference(Multiset(1, 1, 2, 4)), Multiset(1, 3, 4)) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Carthage/Checkouts/Set/SetTests/MultisetCollectionTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Rob Rix. All rights reserved. 2 | 3 | import Set 4 | import XCTest 5 | 6 | final class MultisetCollectionTests: XCTestCase { 7 | func testIndexesElementsByMultiplicity() { 8 | XCTAssertEqual(Multiset(1, 1, 1, 2, 2, 3).map { _ in () }.count, 6) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Carthage/Checkouts/Set/SetTests/MultisetCountTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Rob Rix. All rights reserved. 2 | 3 | import Set 4 | import XCTest 5 | 6 | final class MultisetCountTests: XCTestCase { 7 | func testCountSumsElementsMultiplicities() { 8 | XCTAssertEqual(Multiset(0, 1, 1).count, 3) 9 | } 10 | 11 | func testCountOfAnElementIsItsMultiplicity() { 12 | XCTAssertEqual(Multiset(0, 1, 1).count(1), 2) 13 | } 14 | 15 | func testContainsIsTrueWhenCountIsGreaterThanZero() { 16 | XCTAssert(Multiset(0, 1, 1).contains(0)) 17 | XCTAssert(Multiset(0, 1, 1).contains(1)) 18 | XCTAssertFalse(Multiset(0, 1, 1).contains(2)) 19 | } 20 | 21 | func testNullMultisetIsEmpty() { 22 | XCTAssert(Multiset().isEmpty) 23 | } 24 | 25 | func testNonNullConstructedMultisetIsNotEmpty() { 26 | XCTAssertFalse(Multiset(0).isEmpty) 27 | } 28 | 29 | func testNullConstructedMultisetIsNotEmptyAfterInsertion() { 30 | var set = Multiset() 31 | set.insert(0) 32 | XCTAssertFalse(set.isEmpty) 33 | } 34 | 35 | func testNonNullConstructedMultisetIsEmptyAfterRemoval() { 36 | var set = Multiset(0) 37 | set.remove(0) 38 | XCTAssert(set.isEmpty) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Carthage/Checkouts/Set/SetTests/MultisetHigherOrderFunctionTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014 Rob Rix. All rights reserved. 2 | 3 | import XCTest 4 | import Set 5 | 6 | final class MultisetHigherOrderFunctionTests: XCTestCase { 7 | func testFilter() { 8 | XCTAssert(Multiset(1, 2, 3).filter { $0 == 2 } == Multiset(2)) 9 | } 10 | 11 | func testReducible() { 12 | XCTAssert(Multiset(1, 2, 3).reduce(0, +) == 6) 13 | } 14 | 15 | func testMappable() { 16 | XCTAssert(Multiset(1, 2, 3).map(String.init) == Multiset("1", "2", "3")) 17 | } 18 | 19 | func testFlatMapReturnsTheUnionOfAllResultingSets() { 20 | XCTAssertEqual(Multiset(1, 2).flatMap { [$0, $0 * 2] }, Multiset(1, 2, 2, 4)) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Carthage/Checkouts/Set/SetTests/MultisetInclusionTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Rob Rix. All rights reserved. 2 | 3 | import Set 4 | import XCTest 5 | 6 | final class MultisetInclusionTests: XCTestCase { 7 | func testSubset() { 8 | XCTAssert(Multiset(1).subset(Multiset(1, 2, 3))) 9 | } 10 | 11 | func testStrictSubset() { 12 | XCTAssert(Multiset(1).strictSubset(Multiset(1, 2))) 13 | XCTAssertFalse(Multiset(1).strictSubset(Multiset(1))) 14 | } 15 | 16 | func testSubsetIncludesSelf() { 17 | XCTAssert(Multiset(1, 2, 3).subset(Multiset(1, 2, 3))) 18 | } 19 | 20 | func testSubsetIncludesSmallerMultiplicities() { 21 | XCTAssert(Multiset(1, 2, 3).subset(Multiset(1, 1, 2, 3))) 22 | } 23 | 24 | func testStrictSupersetIsNotSubset() { 25 | XCTAssertFalse(Multiset(1, 2, 3, 4).subset(Multiset(1, 2, 3))) 26 | } 27 | 28 | func testEmptySetIsAlwaysSubset() { 29 | XCTAssert(Multiset().subset(Multiset())) 30 | XCTAssert(Multiset().subset(Multiset(1, 2, 3))) 31 | } 32 | 33 | func testSuperset() { 34 | XCTAssert(Multiset(1, 2, 3).superset(Multiset(1))) 35 | } 36 | 37 | func testStrictSuperset() { 38 | XCTAssert(Multiset(1, 2).strictSuperset(Multiset(1))) 39 | XCTAssertFalse(Multiset(1).strictSuperset(Multiset(1))) 40 | } 41 | 42 | func testSupersetIncludesSelf() { 43 | XCTAssert(Multiset(1, 2, 3).superset(Multiset(1, 2, 3))) 44 | } 45 | 46 | func testSupersetIncludesLargerMultiplicities() { 47 | XCTAssert(Multiset(1, 1, 2, 3).superset(Multiset(1, 2, 3))) 48 | } 49 | 50 | func testStrictSubsetIsNotSuperset() { 51 | XCTAssertFalse(Multiset(1, 2, 3).superset(Multiset(1, 2, 3, 4))) 52 | } 53 | 54 | func testAlwaysSupersetOfEmptySet() { 55 | XCTAssert(Multiset().superset(Multiset())) 56 | XCTAssert(Multiset(1, 2, 3).superset(Multiset())) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Carthage/Checkouts/Set/SetTests/MultisetInitializerTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014 Rob Rix. All rights reserved. 2 | 3 | import XCTest 4 | import Set 5 | 6 | final class MultisetInitializerTests: XCTestCase { 7 | func testVariadic() { 8 | XCTAssert(Multiset(1) == Multiset([1])) 9 | XCTAssert(Multiset(1, 2, 3) == Multiset([1, 2, 3])) 10 | } 11 | 12 | func testMinimumCapacity() { 13 | XCTAssert(Multiset(minimumCapacity: 4).isEmpty) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Carthage/Checkouts/Set/SetTests/MultisetPrintableTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014 Rob Rix. All rights reserved. 2 | 3 | import XCTest 4 | import Set 5 | 6 | final class TestElement: NSObject, CustomDebugStringConvertible { 7 | 8 | // MARK: CustomStringConvertible 9 | 10 | override var description: String { 11 | return __FUNCTION__ 12 | } 13 | 14 | // MARK: CustomDebugStringConvertible 15 | 16 | override var debugDescription: String { 17 | return __FUNCTION__ 18 | } 19 | } 20 | 21 | final class MultisetPrintableTests: XCTestCase { 22 | func testDescription() { 23 | XCTAssertEqual(Multiset().description, "{}") 24 | XCTAssertEqual(Multiset(TestElement()).description, "{description}") 25 | } 26 | 27 | func testDebugDescription() { 28 | XCTAssertEqual(Multiset().debugDescription, "{}") 29 | XCTAssertEqual(Multiset(TestElement()).debugDescription, "{debugDescription}") 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /Carthage/Checkouts/Set/SetTests/MultisetSequenceTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Rob Rix. All rights reserved. 2 | 3 | import XCTest 4 | import Set 5 | 6 | final class MultisetSequenceTests: XCTestCase { 7 | func testGeneratorProducesEveryElement() { 8 | XCTAssertEqual(Array(Multiset(0, 1, 2)).sort(), [ 0, 1, 2 ]) 9 | } 10 | 11 | func testGeneratorProducesElementsByMultiplicity() { 12 | XCTAssertEqual(Multiset(1, 1, 1, 2, 2, 3).reduce(0, +), 10) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Carthage/Checkouts/Set/SetTests/PredicateSetTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Rob Rix. All rights reserved. 2 | 3 | import Set 4 | import XCTest 5 | 6 | final class PredicateSetTests: XCTestCase { 7 | func testPredicateSet() { 8 | XCTAssert(PredicateSet { $0 == 1 }.contains(1)) 9 | } 10 | 11 | func testPredicateSetDoesNotContain() { 12 | XCTAssertFalse(PredicateSet { $0 == 1 }.contains(2)) 13 | } 14 | 15 | func testPredicateSetFromSet() { 16 | let set = Set([1,2,3,4]) 17 | let predicateSet = PredicateSet(set) 18 | XCTAssert(predicateSet.contains(4)) 19 | XCTAssertFalse(predicateSet.contains(5)) 20 | } 21 | 22 | func testPredicateSetFromMutiset() { 23 | let set = Multiset(1,1,1,1,2,3,4) 24 | let predicateSet = PredicateSet(set) 25 | XCTAssert(predicateSet.contains(4)) 26 | XCTAssertFalse(predicateSet.contains(5)) 27 | } 28 | 29 | func testSpecialSets() { 30 | XCTAssertFalse(N.contains(2.1)) 31 | XCTAssert(Q.contains(2)) 32 | } 33 | 34 | func testPredicateSetUnion() { 35 | XCTAssert((Q + Z).contains(1.1)) 36 | } 37 | 38 | func testPredicateSetIntersection() { 39 | XCTAssert((Q & Z).contains(2)) 40 | } 41 | 42 | func testPredicateSetComplement() { 43 | XCTAssertFalse(Q.complement(Z).contains(1.0)) 44 | } 45 | } 46 | 47 | // MARK: Fixtures 48 | func isInt(number: Float) -> Bool { 49 | return floor(number) == number 50 | } 51 | 52 | let Q = PredicateSet { _ in true } 53 | let Z = Q & PredicateSet { isInt($0) } 54 | let N = Z & PredicateSet { $0 > 0 } 55 | -------------------------------------------------------------------------------- /Examples.playground/Sources/Benchmarker.swift: -------------------------------------------------------------------------------- 1 | /* 2 | var b = Benchmarker() 3 | 4 | b.start() 5 | // do something 6 | b.stop() 7 | 8 | println("took \(b.milliseconds) ms") 9 | */ 10 | 11 | import Darwin 12 | 13 | public struct Benchmarker { 14 | static var t = mach_timebase_info(numer: 0, denom: 0) 15 | var startTime = UInt64(0) 16 | var duration = UInt64(0) 17 | 18 | public var milliseconds: Double { 19 | return Double(duration) / 1_000_000 20 | } 21 | 22 | public init() { 23 | if Benchmarker.t.denom == 0 { 24 | mach_timebase_info(&Benchmarker.t) 25 | } 26 | } 27 | 28 | public mutating func start() { 29 | startTime = mach_absolute_time() 30 | } 31 | 32 | public mutating func stop() { 33 | let delta = mach_absolute_time() - startTime 34 | duration = (delta * UInt64(Benchmarker.t.numer)) / UInt64(Benchmarker.t.denom) 35 | } 36 | 37 | public mutating func measure(code: () -> ()) -> Double { 38 | start() 39 | code() 40 | stop() 41 | return milliseconds 42 | } 43 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Matteo Battaglio, 2014 Dan Kogai 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 | 23 | -------------------------------------------------------------------------------- /Playground.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //: Playground - noun: a place where people can play 2 | 3 | import SwiftMath 4 | import Set 5 | import Accelerate 6 | 7 | let p = Polynomial(1, 4, 8) 8 | 9 | p.roots() 10 | 11 | let v1 = Vector3(x: 10, y: 20, z: 5) 12 | let v2 = Vector3(x: 10, y: 5, z: 20) 13 | 14 | v1.crossProduct(v2) 15 | 16 | 17 | let v5a: Vector = [1, 1, 1, 1, 1] 18 | let v5b: Vector = [2, 2, 2, 2, 2] 19 | 20 | (v5a + v5b).coordinates 21 | 22 | v5b.squareLength 23 | 24 | let f = factorial(100) 25 | 26 | //let x = Expression() 27 | // 28 | //let expression = sin(x) 29 | // 30 | //expression.evaluateFor(Double.PI/2) 31 | // 32 | //for i in (-100..<100) { 33 | // expression.evaluateFor(Double(i)*0.1) 34 | //} 35 | // 36 | 37 | //extension Array where Element: Float { 38 | // func f() -> Element { 39 | // return 3.0 40 | // } 41 | //} 42 | // 43 | //extension Array where Element: Double { 44 | // func f() -> Element { 45 | // return 3.0 46 | // } 47 | //} 48 | 49 | let po: Double = 0.0 50 | 51 | func vec(elem: T) -> [T] { 52 | return [1.0, 5.0, 2.0] 53 | } 54 | 55 | let x = [1.1, 2.0, 5.0] 56 | let y = [3.0, -4.0, 0.0] 57 | 58 | x.threshold(3) 59 | 60 | add(vec(1.0), vec(2.0)) 61 | 62 | func rango(x: Matrix) -> Int { 63 | var results = x 64 | 65 | var nr = __CLPK_integer(x.order.rows) 66 | var nc = __CLPK_integer(x.order.columns) 67 | var lwork = __CLPK_integer(10*max(nr, nc)) 68 | var work = [__CLPK_real](count: Int(lwork), repeatedValue: 0.0) 69 | var error: __CLPK_integer = 0 70 | let lds = max(nr, nc) 71 | var s = [__CLPK_real](count: Int(lds), repeatedValue: 0.0) 72 | var u = [__CLPK_real](count: Int(nr * nr), repeatedValue: 0.0) 73 | var vt = [__CLPK_real](count: Int(nc), repeatedValue: 0.0) 74 | 75 | var jobu: Int8 = 78 // 'N' 76 | var jobvt: Int8 = 78 // 'N' 77 | 78 | sgesvd_(&jobu, &jobvt, &nr, &nc, &(results.grid), &nc, &s, &u, &nr, &vt, &nc, &work, &lwork, &error) 79 | 80 | print(s) 81 | 82 | let epsilon: Float = 1e-4 83 | return s.lazy.filter { $0 > epsilon }.count 84 | } 85 | 86 | let m: Matrix = Matrix([1.0, 2.0, 3.0], [2.0, 2.0, 2.0], [3.0, 4.0, 5.0]) 87 | 88 | rango(m) 89 | 90 | -------------------------------------------------------------------------------- /Playground.playground/Sources/Benchmarker.swift: -------------------------------------------------------------------------------- 1 | /* 2 | var b = Benchmarker() 3 | 4 | b.start() 5 | // do something 6 | b.stop() 7 | 8 | println("took \(b.milliseconds) ms") 9 | */ 10 | 11 | import Darwin 12 | 13 | public struct Benchmarker { 14 | static var t = mach_timebase_info(numer: 0, denom: 0) 15 | var startTime = UInt64(0) 16 | var duration = UInt64(0) 17 | 18 | public var milliseconds: Double { 19 | return Double(duration) / 1_000_000 20 | } 21 | 22 | public init() { 23 | if Benchmarker.t.denom == 0 { 24 | mach_timebase_info(&Benchmarker.t) 25 | } 26 | } 27 | 28 | public mutating func start() { 29 | startTime = mach_absolute_time() 30 | } 31 | 32 | public mutating func stop() { 33 | let delta = mach_absolute_time() - startTime 34 | duration = (delta * UInt64(Benchmarker.t.numer)) / UInt64(Benchmarker.t.denom) 35 | } 36 | 37 | public mutating func measure(code: () -> ()) -> Double { 38 | start() 39 | code() 40 | stop() 41 | return milliseconds 42 | } 43 | } -------------------------------------------------------------------------------- /Playground.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Playground.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Playground.playground/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SwiftMath 2 | 3 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 4 | 5 | SwiftMath is a Swift framework providing some useful math constructs and functions, like complex numbers, vectors, matrices, quaternions, and polynomials. 6 | 7 | :warning: *SwiftMath is work in progress, in alpha state. Master is currently targeting Swift 2.1.* 8 | 9 | ## Requirements 10 | 11 | SwiftMath requires iOS 8.0+ / OS X 10.9+. 12 | 13 | ## Installation 14 | 15 | SwiftMath can be installed with the dependency manager [Carthage](https://github.com/Carthage/Carthage). 16 | * Add the following line to your project's Cartfile 17 | ``` 18 | github "madbat/SwiftMath" 19 | ``` 20 | * In the terminal, run `carthage update` 21 | * Link your project target(s) with the built frameworks. Application targets should also ensure that the framework gets copied into their application bundle. 22 | 23 | ## Usage 24 | 25 | ### Vector3 26 | 27 | Vector3 — as the name suggests — represents a vector in the three-dimensional Euclidean space (aka R×R×R). 28 | Some of the most common uses of 3D vectors consist in encoding physical quantities like position, velocity, acceleration, force, and many others. 29 | 30 | ```swift 31 | let v1 = Vector3(x: 1, y: 2, z: 3) 32 | let v2 = Vector3(x: 5, y: 6, z: 7) 33 | 34 | // vector sum 35 | let v3 = v1 + v2 // Vector3(x: 6, y: 8, z: 10) 36 | 37 | // length 38 | v3.length // equals v3.norm 39 | 40 | // zero vector 41 | Vector3.zero() // Vector3(x: 0, y: 0, z: 0) 42 | 43 | // unit-length vector 44 | v3.unit() // divides v3 by its length 45 | ``` 46 | 47 | ### Vector2 48 | 49 | Pretty much like `Vector3`, but for 2D vectors. 50 | 51 | ### Complex 52 | 53 | Complex numbers extend real numbers in order to solve problems that cannot be solved with real numbers alone. 54 | For example, the roots of a polynomial equation of degree > 1 can always be expressed with complex numbers, but not with real numbers. 55 | 56 | ```swift 57 | // the default constructor for Complex takes the real and imaginary parts as parameters 58 | let c1 = Complex(1.0, 3.0) 59 | c1.re // 1.0 60 | c1.im // 3.0 61 | 62 | // a complex can also be constructed by using the property i defined on Float and Double 63 | let c2 = 5 + 1.i // Complex(5.0, 1.0) 64 | 65 | // complex conjugate 66 | c2.conj() // Complex(5.0, -1.0) 67 | 68 | // polar form 69 | let c3 = Complex(abs: 2.0, arg: -4.0) 70 | 71 | let realComplex = Complex(10.0, 0.0) 72 | realComplex.isReal // true 73 | ``` 74 | 75 | ### Quaternion 76 | 77 | Quaternions extend complex numbers to 4 dimensions. 78 | They're handy to rotate three-dimensional vectors. 79 | 80 | ```swift 81 | // rotating a vector by π/2 around its x axis 82 | let original = Vector3(x: 3, y: 4, z: 0) 83 | let rotation = Quaternion(axis: Vector3(x: 1, y: 0, z: 0), angle: Double.PI/2.0) 84 | let rotated = original.rotate(rotation) // Vector3(x: 3, y: 0, z: 4.0) 85 | ``` 86 | 87 | ### Polynomial 88 | 89 | Polynomial lets you represent – and find the roots of – a polynomial expression. 90 | 91 | The following snippet shows how to express the polynomial `x^2 + 4x + 8` 92 | ```swift 93 | let p = Polynomial(1, 4, 8) 94 | ``` 95 | 96 | Use Polynomial's `roots()` method to calculate its roots, represented as a (multi)set of complex numbers: 97 | ```swift 98 | p.roots() // returns { (-2 - 2i), (-2 + 2i) } 99 | ``` 100 | For polynomials of degree <= 4, `roots()` defaults to using the analytic method, while for polynomials of higher degrees it uses the the [Durand-Kerner method](http://en.wikipedia.org/wiki/Durand%E2%80%93Kerner_method). 101 | It is possible to force the root finding process to use the numeric method also for polynomials 102 | of degree <= 4, using `roots(preferClosedFormSolution: false)`. 103 | 104 | ## Contributing 105 | 106 | Contributions in any form (especially pull requests) are _very_ welcome! 107 | 108 | ## License 109 | 110 | SwiftMath is released under the MIT License. See the [LICENSE](https://github.com/madbat/SwiftMath/blob/master/LICENSE) file for more info. 111 | -------------------------------------------------------------------------------- /SwiftMath.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SwiftMath.xcodeproj/xcshareddata/xcschemes/SwiftMath-Mac.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 78 | 79 | 85 | 86 | 87 | 88 | 89 | 90 | 96 | 97 | 103 | 104 | 105 | 106 | 108 | 109 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /SwiftMath.xcodeproj/xcshareddata/xcschemes/SwiftMath-iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 78 | 79 | 85 | 86 | 87 | 88 | 89 | 90 | 96 | 97 | 103 | 104 | 105 | 106 | 108 | 109 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /SwiftMath.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /SwiftMath.xcworkspace/xcshareddata/SwiftMath.xcscmblueprint: -------------------------------------------------------------------------------- 1 | { 2 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "97555501B95738B317CD1497A64FF46A22826C24", 3 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { 4 | 5 | }, 6 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { 7 | "A446EC52AB68AB3BEF60C80CCCF3CA89E9A68DB1" : 0, 8 | "97555501B95738B317CD1497A64FF46A22826C24" : 0 9 | }, 10 | "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "6BFCD71F-79A5-457C-A735-AE60BD77DCDB", 11 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { 12 | "A446EC52AB68AB3BEF60C80CCCF3CA89E9A68DB1" : "Set\/", 13 | "97555501B95738B317CD1497A64FF46A22826C24" : "SwiftMath\/" 14 | }, 15 | "DVTSourceControlWorkspaceBlueprintNameKey" : "SwiftMath", 16 | "DVTSourceControlWorkspaceBlueprintVersion" : 203, 17 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "SwiftMath.xcworkspace", 18 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ 19 | { 20 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/madbat\/SwiftMath.git", 21 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 22 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "97555501B95738B317CD1497A64FF46A22826C24" 23 | }, 24 | { 25 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/madbat\/Set.git", 26 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 27 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "A446EC52AB68AB3BEF60C80CCCF3CA89E9A68DB1" 28 | } 29 | ] 30 | } -------------------------------------------------------------------------------- /SwiftMath/Benchmarker.swift: -------------------------------------------------------------------------------- 1 | /* 2 | var b = Benchmarker() 3 | 4 | b.start() 5 | // do something 6 | b.stop() 7 | 8 | println("took \(b.milliseconds) ms") 9 | */ 10 | 11 | import Darwin 12 | 13 | public struct Benchmarker { 14 | static var t = mach_timebase_info(numer: 0, denom: 0) 15 | var startTime = UInt64(0) 16 | var duration = UInt64(0) 17 | 18 | public var milliseconds: Double { 19 | return Double(duration) / 1_000_000 20 | } 21 | 22 | public init() { 23 | if Benchmarker.t.denom == 0 { 24 | mach_timebase_info(&Benchmarker.t) 25 | } 26 | } 27 | 28 | public mutating func start() { 29 | startTime = mach_absolute_time() 30 | } 31 | 32 | public mutating func stop() { 33 | let delta = mach_absolute_time() - startTime 34 | duration = (delta * UInt64(Benchmarker.t.numer)) / UInt64(Benchmarker.t.denom) 35 | } 36 | 37 | private static func millis(delta: UInt64) -> Double { 38 | return Double((delta * UInt64(Benchmarker.t.numer)) / (UInt64(Benchmarker.t.denom) * 1_000_000)) 39 | } 40 | 41 | public static func measure(code: () -> ()) -> Double { 42 | let startTime = mach_absolute_time() 43 | code() 44 | let delta = mach_absolute_time() - startTime 45 | return Benchmarker.millis(delta) 46 | } 47 | 48 | public mutating func measure(code: () -> ()) -> Double { 49 | start() 50 | code() 51 | stop() 52 | return milliseconds 53 | } 54 | } -------------------------------------------------------------------------------- /SwiftMath/Complex.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Complex.swift 3 | // SwiftMath 4 | // 5 | // Created by Dan Kogai on 6/12/14. 6 | // Copyright (c) 2014 Dan Kogai, Matteo Battaglio. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension Double { 12 | /// self * 1.0i 13 | public var i: Complex { 14 | return Complex(0.0, self) 15 | } 16 | } 17 | 18 | extension Float { 19 | /// self * 1.0i 20 | public var i: Complex { 21 | return Complex(0.0, self) 22 | } 23 | } 24 | 25 | public struct Complex { 26 | 27 | public let (re, im): (T, T) 28 | 29 | public let isReal: Bool 30 | 31 | public init(_ re: T, _ im: T) { 32 | self.re = re 33 | self.im = im 34 | isReal = im =~ T(0) 35 | } 36 | 37 | public init() { 38 | self.init(T(0), T(0)) 39 | } 40 | 41 | public init(abs: T, arg: T) { 42 | self.init(abs * arg.cos(), abs * arg.sin()) 43 | } 44 | 45 | public static func id() -> Complex { 46 | return Complex(1.0, 0.0) 47 | } 48 | 49 | public static func zero() -> Complex { 50 | return Complex(0.0, 0.0) 51 | } 52 | 53 | public var isZero: Bool { 54 | return re.isZero && im.isZero 55 | } 56 | 57 | /// absolute value thereof 58 | public var abs: T { 59 | return re.hypot(im) 60 | } 61 | 62 | /// argument thereof 63 | public var arg: T { 64 | return im.atan2(re) 65 | } 66 | 67 | /// norm thereof 68 | public var norm: T { 69 | return re.hypot(im) 70 | } 71 | 72 | /// conjugate thereof 73 | public func conj() -> Complex { 74 | return Complex(re, -im) 75 | } 76 | 77 | public func reciprocal() -> Complex { 78 | let length = norm 79 | return conj() / (length * length) 80 | } 81 | 82 | /// projection thereof 83 | public func proj() -> Complex { 84 | if re.isFinite && im.isFinite { 85 | return self 86 | } else { 87 | return Complex(T(1)/T(0), im.isSignMinus ? -T(0) : T(0)) 88 | } 89 | } 90 | 91 | /// (real, imag) 92 | public var tuple: (T, T) { 93 | return (re, im) 94 | } 95 | 96 | /// z * i 97 | public var i: Complex { 98 | return Complex(-im, re) 99 | } 100 | 101 | /// .hashvalue -- conforms to Hashable 102 | 103 | } 104 | 105 | extension Complex: Hashable { 106 | 107 | public var hashValue: Int { // take most significant halves and join 108 | let bits = sizeof(Int) * 4 109 | let mask = bits == 16 ? 0xffff : 0x7fffFFFF 110 | return (re.hashValue & ~mask) | (im.hashValue >> bits) 111 | } 112 | 113 | } 114 | 115 | public func == (lhs: Complex, rhs: Complex) -> Bool { 116 | return lhs.re == rhs.re && lhs.im == rhs.im 117 | } 118 | 119 | public func == (lhs: Complex, rhs: T) -> Bool { 120 | return lhs.re == rhs && lhs.im.isZero 121 | } 122 | 123 | public func == (lhs: T, rhs: Complex) -> Bool { 124 | return rhs.re == lhs && rhs.im.isZero 125 | } 126 | 127 | extension Complex: CustomStringConvertible { 128 | 129 | public var description: String { 130 | let plus = im.isSignMinus ? "" : "+" 131 | return "(\(re)\(plus)\(im).i)" 132 | } 133 | 134 | } 135 | 136 | // operator definitions 137 | infix operator ** { associativity right precedence 170 } 138 | infix operator **= { associativity right precedence 90 } 139 | infix operator =~ { associativity none precedence 130 } 140 | infix operator !~ { associativity none precedence 130 } 141 | 142 | 143 | 144 | // +, += 145 | public prefix func + (z: Complex) -> Complex { 146 | return z 147 | } 148 | 149 | public func + (lhs: Complex, rhs: Complex) -> Complex { 150 | return Complex(lhs.re + rhs.re, lhs.im + rhs.im) 151 | } 152 | 153 | public func + (lhs: Complex, rhs: T) -> Complex { 154 | return lhs + Complex(rhs, T(0)) 155 | } 156 | 157 | public func + (lhs: T, rhs: Complex) -> Complex { 158 | return Complex(lhs, T(0)) + rhs 159 | } 160 | 161 | public func += (inout lhs: Complex, rhs: Complex) { 162 | lhs = Complex(lhs.re + rhs.re, lhs.im + rhs.im) 163 | } 164 | 165 | public func += (inout lhs: Complex, rhs: T) { 166 | lhs = Complex(lhs.re + rhs, lhs.im) 167 | } 168 | 169 | // -, -= 170 | public prefix func - (z: Complex) -> Complex { 171 | return Complex(-z.re, -z.im) 172 | } 173 | 174 | public func - (lhs: Complex, rhs: Complex) -> Complex { 175 | return Complex(lhs.re - rhs.re, lhs.im - rhs.im) 176 | } 177 | 178 | public func - (lhs: Complex, rhs: T) -> Complex { 179 | return lhs - Complex(rhs, T(0)) 180 | } 181 | 182 | public func - (lhs: T, rhs: Complex) -> Complex { 183 | return Complex(lhs, T(0)) - rhs 184 | } 185 | 186 | public func -= (inout lhs: Complex, rhs: Complex) { 187 | lhs = Complex(lhs.re - rhs.re, lhs.im - rhs.im) 188 | } 189 | 190 | public func -= (inout lhs: Complex, rhs: T) { 191 | lhs = Complex(lhs.re - rhs, lhs.im) 192 | } 193 | 194 | // *, *= 195 | public func * (lhs: Complex, rhs: Complex) -> Complex { 196 | return Complex( 197 | lhs.re * rhs.re - lhs.im * rhs.im, 198 | lhs.re * rhs.im + lhs.im * rhs.re 199 | ) 200 | } 201 | 202 | public func * (lhs: Complex, rhs: T) -> Complex { 203 | return Complex(lhs.re * rhs, lhs.im * rhs) 204 | } 205 | 206 | public func * (lhs: T, rhs: Complex) -> Complex { 207 | return Complex(lhs * rhs.re, lhs * rhs.im) 208 | } 209 | 210 | public func *= (inout lhs: Complex, rhs: Complex) { 211 | lhs = lhs * rhs 212 | } 213 | 214 | public func *= (inout lhs: Complex, rhs: T) { 215 | lhs = lhs * rhs 216 | } 217 | 218 | // /, /= 219 | // 220 | // cf. https://github.com/dankogai/swift-complex/issues/3 221 | // 222 | public func / (lhs: Complex, rhs: Complex) -> Complex { 223 | if rhs.re.abs >= rhs.im.abs { 224 | let r = rhs.im / rhs.re 225 | let d = rhs.re + rhs.im * r 226 | return Complex ( 227 | (lhs.re + lhs.im * r) / d, 228 | (lhs.im - lhs.re * r) / d 229 | ) 230 | } else { 231 | let r = rhs.re / rhs.im 232 | let d = rhs.re * r + rhs.im 233 | return Complex ( 234 | (lhs.re * r + lhs.im) / d, 235 | (lhs.im * r - lhs.re) / d 236 | ) 237 | 238 | } 239 | } 240 | 241 | public func / (lhs: Complex, rhs: T) -> Complex { 242 | return Complex(lhs.re / rhs, lhs.im / rhs) 243 | } 244 | 245 | public func / (lhs: T, rhs: Complex) -> Complex { 246 | return Complex(lhs, T(0)) / rhs 247 | } 248 | 249 | public func /= (inout lhs: Complex, rhs:Complex) { 250 | lhs = lhs / rhs 251 | } 252 | 253 | public func /= (inout lhs: Complex, rhs: T) { 254 | lhs = lhs / rhs 255 | } 256 | 257 | // exp(z) 258 | public func exp(z: Complex) -> Complex { 259 | let abs = z.re.exp() 260 | let arg = z.im 261 | return Complex(abs * arg.cos(), abs * arg.sin()) 262 | } 263 | 264 | // log(z) 265 | public func log(z: Complex) -> Complex { 266 | return Complex(z.abs.log(), z.arg) 267 | } 268 | 269 | // log10(z) -- just because C++ has it 270 | public func log10(z: Complex) -> Complex { 271 | return log(z) / T(log(10.0)) 272 | } 273 | 274 | public func log10(r: T) -> T { 275 | return r.log() / T(log(10.0)) 276 | } 277 | 278 | // pow(b, x) 279 | public func pow(lhs: Complex, _ rhs: Complex) -> Complex { 280 | if rhs.isZero { 281 | return Complex(T(1), T(0)) // x ** 0 == 1 282 | } else if lhs.isZero && rhs.isReal && rhs.re > T(0) { 283 | return Complex.zero() // 0 ** x == 0 (when x > 0) 284 | } else if lhs.isReal && lhs.re > T(0) { // b^z == e^(z*ln(b)) (when b is a positive real number) 285 | let z = log(lhs) * rhs 286 | return exp(z) 287 | } else { 288 | // FIXME: Implement general case of complex powers of complex numbers the right way 289 | let z = log(lhs) * rhs 290 | return exp(z) 291 | } 292 | } 293 | 294 | public func pow(lhs: Complex, _ rhs: T) -> Complex { 295 | return pow(lhs, Complex(rhs, T(0))) 296 | } 297 | 298 | public func pow(lhs:T, _ rhs: Complex) -> Complex { 299 | return pow(Complex(lhs, T(0)), rhs) 300 | } 301 | 302 | // **, **= 303 | public func ** (lhs: T, rhs: T) -> T { 304 | return lhs.pow(rhs) 305 | } 306 | 307 | public func ** (lhs: Complex, rhs: Complex) -> Complex { 308 | return pow(lhs, rhs) 309 | } 310 | 311 | public func ** (lhs: T, rhs: Complex) -> Complex { 312 | return pow(lhs, rhs) 313 | } 314 | 315 | public func ** (lhs: Complex, rhs: T) -> Complex { 316 | return pow(lhs, rhs) 317 | } 318 | 319 | public func **= (inout lhs: T, rhs: T) { 320 | lhs = lhs.pow(rhs) 321 | } 322 | 323 | public func **= (inout lhs: Complex, rhs: Complex) { 324 | lhs = pow(lhs, rhs) 325 | } 326 | 327 | public func **= (inout lhs: Complex, rhs: T) { 328 | lhs = pow(lhs, rhs) 329 | } 330 | 331 | // sqrt(z) 332 | public func sqrt(z: Complex) -> Complex { 333 | // return z ** 0.5 334 | if z.isReal && z.re >= 0.0 { 335 | return Complex(z.re.sqrt(), 0.0) 336 | } 337 | 338 | let d = z.abs 339 | let re = ((z.re + d)/T(2)).sqrt() 340 | if z.im < T(0) { 341 | return Complex(re, -((-z.re + d)/T(2)).sqrt()) 342 | } else { 343 | return Complex(re, ((-z.re + d)/T(2)).sqrt()) 344 | } 345 | } 346 | 347 | // cos(z) 348 | public func cos(z: Complex) -> Complex { 349 | return (exp(z.i) + exp(-z.i)) / T(2) 350 | } 351 | 352 | // sin(z) 353 | public func sin(z:Complex) -> Complex { 354 | return -(exp(z.i) - exp(-z.i)).i / T(2) 355 | } 356 | 357 | // tan(z) 358 | public func tan(z: Complex) -> Complex { 359 | let ezi = exp(z.i), e_zi = exp(-z.i) 360 | return (ezi - e_zi) / (ezi + e_zi).i 361 | } 362 | 363 | // atan(z) 364 | public func atan(z: Complex) -> Complex { 365 | let l0 = log(T(1) - z.i), l1 = log(T(1) + z.i) 366 | return (l0 - l1).i / T(2) 367 | } 368 | 369 | public func atan(r: T) -> T { 370 | return atan(Complex(r, T(0))).re 371 | } 372 | 373 | // atan2(z, zz) 374 | func atan2(z: Complex, zz: Complex) -> Complex { 375 | return atan(z / zz) 376 | } 377 | 378 | // asin(z) 379 | public func asin(z: Complex) -> Complex { 380 | return -log(z.i + sqrt(T(1) - z*z)).i 381 | } 382 | 383 | // acos(z) 384 | public func acos(z: Complex) -> Complex { 385 | return log(z - sqrt(T(1) - z*z).i).i 386 | } 387 | 388 | // sinh(z) 389 | public func sinh(z: Complex) -> Complex { 390 | return (exp(z) - exp(-z)) / T(2) 391 | } 392 | 393 | // cosh(z) 394 | public func cosh(z: Complex) -> Complex { 395 | return (exp(z) + exp(-z)) / T(2) 396 | } 397 | 398 | // tanh(z) 399 | public func tanh(z: Complex) -> Complex { 400 | let ez = exp(z), e_z = exp(-z) 401 | return (ez - e_z) / (ez + e_z) 402 | } 403 | 404 | // asinh(z) 405 | public func asinh(z: Complex) -> Complex { 406 | return log(z + sqrt(z*z + T(1))) 407 | } 408 | 409 | // acosh(z) 410 | public func acosh(z: Complex) -> Complex { 411 | return log(z + sqrt(z*z - T(1))) 412 | } 413 | 414 | // atanh(z) 415 | public func atanh(z: Complex) -> Complex { 416 | let t = log((1.0 + z)/(1.0 - z)) 417 | return t / 2.0 418 | } 419 | 420 | // for the compatibility's sake w/ C++11 421 | public func abs(z: Complex) -> T { return z.abs } 422 | public func arg(z: Complex) -> T { return z.arg } 423 | public func real(z: Complex) -> T { return z.re } 424 | public func imag(z: Complex) -> T { return z.im } 425 | public func norm(z: Complex) -> T { return z.norm } 426 | public func conj(z: Complex) -> Complex { return z.conj() } 427 | public func proj(z: Complex) -> Complex { return z.proj() } 428 | 429 | // 430 | // approximate comparisons 431 | // 432 | public func =~ (lhs: Complex, rhs: Complex) -> Bool { 433 | if lhs == rhs { 434 | return true 435 | } 436 | return lhs.abs =~ rhs.abs 437 | } 438 | 439 | public func =~ (lhs: Complex, rhs: T) -> Bool { 440 | return lhs.abs =~ rhs.abs 441 | } 442 | 443 | public func =~ (lhs: T, rhs: Complex) -> Bool { 444 | return lhs.abs =~ rhs.abs 445 | } 446 | 447 | public func !~ (lhs: Complex, rhs: Complex) -> Bool { 448 | return !(lhs =~ rhs) 449 | } 450 | 451 | func !~ (lhs: Complex, rhs: T) -> Bool { 452 | return !(lhs =~ rhs) 453 | } 454 | 455 | func !~ (lhs: T, rhs: Complex) -> Bool { 456 | return !(lhs =~ rhs) 457 | } 458 | 459 | // typealiases 460 | typealias Complex64 = Complex 461 | typealias Complex32 = Complex 462 | -------------------------------------------------------------------------------- /SwiftMath/Expression.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Expression.swift 3 | // SwiftMath 4 | // 5 | // Created by Matteo Battaglio on 25/07/15. 6 | // Copyright © 2015 Matteo Battaglio. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum Operation { 12 | case Unary(function: (Double) -> Double) 13 | case Binary(value: Double, function: (Double, Double) -> Double, direction: Direction) 14 | } 15 | 16 | enum Direction { 17 | case ExprThenValue 18 | case ValueThenExpr 19 | } 20 | 21 | public struct Expression { 22 | 23 | var operations: [Operation] = [] 24 | 25 | public init() { 26 | 27 | } 28 | 29 | init(_ operations: [Operation]) { 30 | self.operations = operations 31 | } 32 | 33 | public func evaluateFor(variableValue: Double) -> Double { 34 | return operations.reduce(variableValue) { (exprValue, operation) in 35 | switch operation { 36 | case let .Unary(function): 37 | return function(exprValue) 38 | case let .Binary(value, function, direction): 39 | return direction == .ExprThenValue ? function(exprValue, value) : function(value, exprValue) 40 | } 41 | } 42 | } 43 | 44 | func composeWith(value value: Double, function: (Double, Double) -> Double, direction: Direction) -> Expression { 45 | return Expression(self.operations + [.Binary(value: value, function: function, direction: direction)]) 46 | } 47 | 48 | func composeWith(function function: (Double) -> Double) -> Expression { 49 | return Expression(self.operations + [.Unary(function: function)]) 50 | } 51 | 52 | // func evaluate(#interval: Interval, step: Interval.Element) -> Domain { 53 | // return Domain() 54 | // } 55 | 56 | } 57 | 58 | // MARK: - Binary functions 59 | 60 | // MARK: Arithmetic functions 61 | 62 | public func +(lhs: Expression, rhs: Double) -> Expression { 63 | return lhs.composeWith(value: rhs, function: +, direction: .ExprThenValue) 64 | } 65 | 66 | public func +(lhs: Double, rhs: Expression) -> Expression { 67 | return rhs.composeWith(value: lhs, function: +, direction: .ValueThenExpr) 68 | } 69 | 70 | public func -(lhs: Expression, rhs: Double) -> Expression { 71 | return lhs.composeWith(value: rhs, function: -, direction: .ExprThenValue) 72 | } 73 | 74 | public func -(lhs: Double, rhs: Expression) -> Expression { 75 | return rhs.composeWith(value: lhs, function: -, direction: .ValueThenExpr) 76 | } 77 | 78 | public func *(lhs: Expression, rhs: Double) -> Expression { 79 | return lhs.composeWith(value: rhs, function: *, direction: .ExprThenValue) 80 | } 81 | 82 | public func *(lhs: Double, rhs: Expression) -> Expression { 83 | return rhs.composeWith(value: lhs, function: *, direction: .ValueThenExpr) 84 | } 85 | 86 | public func /(lhs: Expression, rhs: Double) -> Expression { 87 | return lhs.composeWith(value: rhs, function: /, direction: .ExprThenValue) 88 | } 89 | 90 | public func /(lhs: Double, rhs: Expression) -> Expression { 91 | return rhs.composeWith(value: lhs, function: /, direction: .ValueThenExpr) 92 | } 93 | 94 | // MARK: Algebraic functions 95 | 96 | public func pow(lhs: Expression, _ rhs: Double) -> Expression { 97 | return lhs.composeWith(value: rhs, function: pow, direction: .ExprThenValue) 98 | } 99 | 100 | public func pow(lhs: Double, _ rhs: Expression) -> Expression { 101 | return rhs.composeWith(value: lhs, function: pow, direction: .ValueThenExpr) 102 | } 103 | 104 | infix operator ** { associativity left precedence 160 } 105 | 106 | public func **(lhs: Expression, rhs: Double) -> Expression { 107 | return pow(lhs, rhs) 108 | } 109 | 110 | public func **(lhs: Double, rhs: Expression) -> Expression { 111 | return pow(lhs, rhs) 112 | } 113 | 114 | // MARK: - Unary functions 115 | 116 | // MARK: Factorial function 117 | 118 | public let factorial = memoize(_factorial) 119 | 120 | private func _factorial(x: Int) -> Double { 121 | precondition(x >= 0, "Factorial is undefined for negative numbers") 122 | var result = 1.0 123 | for var i = Double(x); i > 1; i-- { 124 | result *= i 125 | } 126 | return result 127 | } 128 | 129 | public func factorial(x: Double) -> Double { 130 | return factorial(Int(x)) 131 | } 132 | 133 | public func factorial(x: Expression) -> Expression { 134 | return x.composeWith(function: factorial) 135 | } 136 | 137 | // MARK: Trigonometric functions 138 | 139 | public func cos(x: Expression) -> Expression { 140 | return x.composeWith(function: cos) 141 | } 142 | 143 | public func sin(x: Expression) -> Expression { 144 | return x.composeWith(function: sin) 145 | } 146 | 147 | public func tan(x: Expression) -> Expression { 148 | return x.composeWith(function: tan) 149 | } 150 | 151 | public func acos(x: Expression) -> Expression { 152 | return x.composeWith(function: acos) 153 | } 154 | 155 | public func asin(x: Expression) -> Expression { 156 | return x.composeWith(function: asin) 157 | } 158 | 159 | public func atan(x: Expression) -> Expression { 160 | return x.composeWith(function: atan) 161 | } 162 | 163 | // MARK: Hyperbolic functions 164 | 165 | public func cosh(x: Expression) -> Expression { 166 | return x.composeWith(function: cosh) 167 | } 168 | 169 | public func sinh(x: Expression) -> Expression { 170 | return x.composeWith(function: sinh) 171 | } 172 | 173 | public func tanh(x: Expression) -> Expression { 174 | return x.composeWith(function: tanh) 175 | } 176 | 177 | public func acosh(x: Expression) -> Expression { 178 | return x.composeWith(function: acosh) 179 | } 180 | 181 | public func asinh(x: Expression) -> Expression { 182 | return x.composeWith(function: asinh) 183 | } 184 | 185 | public func atanh(x: Expression) -> Expression { 186 | return x.composeWith(function: atanh) 187 | } 188 | -------------------------------------------------------------------------------- /SwiftMath/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 0.2 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /SwiftMath/MatrixType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MatrixType.swift 3 | // SwiftMath 4 | // 5 | // Created by Matteo Battaglio on 25/07/15. 6 | // Copyright © 2015 Matteo Battaglio. All rights reserved. 7 | // 8 | 9 | public protocol MatrixType: ArrayLiteralConvertible { 10 | 11 | typealias MatrixElement: RealType 12 | 13 | typealias Order = (rows: Int, columns: Int) 14 | 15 | init(_ rows: [[MatrixElement]]) 16 | 17 | init(_ rows: [MatrixElement]...) 18 | 19 | // var rows: ArraySlice { get } 20 | // 21 | // var columns: ArraySlice { get } 22 | 23 | var order: Order { get } 24 | 25 | // var rank: Int { get } 26 | 27 | } 28 | 29 | extension MatrixType { 30 | 31 | public init(_ rows: [MatrixElement]...) { 32 | self.init(rows) 33 | } 34 | 35 | public init(arrayLiteral elements: [MatrixElement]...) { 36 | self.init(elements) 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /SwiftMath/Memoize.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Memoize.swift 3 | // SwiftMath 4 | // 5 | // Created by Matteo Battaglio on 25/07/15. 6 | // Copyright © 2015 Matteo Battaglio. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public func memoize(fn: Input -> Output) -> (Input) -> Output { 12 | var cache = [Input: Output]() 13 | return { val in 14 | if let value = cache[val] { 15 | return value 16 | } else { 17 | let newValue = fn(val) 18 | cache[val] = newValue 19 | return newValue 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /SwiftMath/Polynomial.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Polinomial.swift 3 | // SwiftMath 4 | // 5 | // Created by Matteo Battaglio on 08/01/15. 6 | // Copyright (c) 2015 Matteo Battaglio. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Set 11 | 12 | public struct Polynomial: Equatable { 13 | 14 | let coefficients: [Real] 15 | 16 | /** 17 | Creates a new instance of `Polynomial` with the given coefficients. 18 | 19 | :param: coefficients The coefficients for the terms of the polinomial, ordered from the coefficient for the highest-degree term to the coefficient for the 0 degree term. 20 | */ 21 | public init(_ coefficients: Real...) { 22 | self.init(coefficients) 23 | } 24 | 25 | /** 26 | Creates a new instance of `Polynomial` with the given coefficients. 27 | 28 | :param: coefficients The coefficients for the terms of the polinomial, ordered from the coefficient for the highest-degree term to the coefficient for the 0 degree term. 29 | */ 30 | public init(_ coefficients: [Real]) { 31 | if coefficients.count == 0 || (coefficients.count == 1 && coefficients[0].isZero) { 32 | preconditionFailure("the zero polynomial is undefined") 33 | } 34 | self.coefficients = coefficients 35 | } 36 | 37 | /// The grade of the polinomial. It's equal to the number of coefficient minus one. 38 | public var degree: Int { 39 | return coefficients.count - 1 40 | } 41 | 42 | /// Finds the roots of the polinomial. 43 | public func roots(preferClosedFormSolution preferClosedFormSolution: Bool = true) -> Multiset> { 44 | if (preferClosedFormSolution && degree <= 4) { 45 | switch degree { 46 | case 0: 47 | return [] // Empty set (i.e. no solutions to `k = 0`, when k != 0) 48 | case 1: 49 | return linear() 50 | case 2: 51 | return quadratic() 52 | case 3: 53 | return cubic() 54 | case 4: 55 | return quartic() 56 | default: 57 | fatalError("Not reachable") 58 | } 59 | } else { 60 | return durandKernerMethod() 61 | } 62 | } 63 | 64 | // MARK: Private methods 65 | 66 | private func linear() -> Multiset> { 67 | let a = coefficients[0] 68 | let b = coefficients[1] 69 | 70 | if a.isZero { 71 | return [] 72 | } 73 | 74 | let x = -b/a 75 | return [Complex(x, 0.0)] 76 | } 77 | 78 | private func quadratic() -> Multiset> { 79 | let a = coefficients[0] 80 | let b = coefficients[1] 81 | let c = coefficients[2] 82 | 83 | if a.isZero { 84 | return Polynomial(b, c).roots() 85 | } 86 | 87 | if c.isZero { 88 | return [Complex.zero()] + Polynomial(a, b).roots() 89 | } 90 | 91 | let discriminant = (b * b) - (4.0 * a * c) 92 | var dSqrt = sqrt(Complex(discriminant, 0.0)) 93 | if b.isSignMinus { 94 | dSqrt = -dSqrt 95 | } 96 | let x1 = -(b + dSqrt) / (2.0 * a) 97 | let x2 = c / (a * x1) 98 | 99 | return [x1, x2] 100 | } 101 | 102 | private func cubic() -> Multiset> { 103 | let a = coefficients[0] 104 | var b = coefficients[1] 105 | var c = coefficients[2] 106 | var d = coefficients[3] 107 | 108 | if a.isZero { 109 | return Polynomial(b, c, d).roots() 110 | } 111 | if d.isZero { 112 | return [Complex.zero()] + Polynomial(a, b, c).roots() 113 | } 114 | if a != Real(1) { 115 | b /= a 116 | c /= a 117 | d /= a 118 | } 119 | 120 | let b2 = b*b 121 | let b3 = b2*b 122 | 123 | let D0 = b2 - (3.0 * c) 124 | let bc9 = 9.0 * b * c 125 | let D1 = (2.0 * b3) - bc9 + (27.0 * d) 126 | let D12 = D1 * D1 127 | let D03 = D0 * D0 * D0 128 | let minus27D = D12 - (4.0 * D03) 129 | var squareRoot = sqrt(Complex(minus27D, 0.0)) 130 | let oneThird: Real = 1.0/3.0 131 | let zero: Real = 0.0 132 | 133 | switch (D0.isZero, minus27D.isZero) { 134 | case (true, true): 135 | let x = Complex(-oneThird * b, zero) 136 | return [x, x, x] 137 | case (false, true): 138 | let d9 = 9.0 * d 139 | let bc4 = 4.0 * b * c 140 | let x12 = Complex((d9 - b * c) / (2.0 * D0), zero) 141 | let x3 = Complex((bc4 - d9 - b3) / D0, zero) 142 | return [x12, x12, x3] 143 | case (true, false): 144 | if (D1 + squareRoot) == zero { 145 | squareRoot = -squareRoot 146 | } 147 | fallthrough 148 | default: 149 | let C = pow(0.5 * (D1 + squareRoot), oneThird) 150 | 151 | let im = Complex(0.0, Real(0.5*sqrt(3.0))) 152 | let u2 = Real(-0.5) + im 153 | let u3 = Real(-0.5) - im 154 | let u2C = u2 * C 155 | let u3C = u3 * C 156 | 157 | let x13 = b + C + (D0 / C) 158 | let x23 = b + u2C + (D0 / u2C) 159 | let x33 = b + u3C + (D0 / u3C) 160 | 161 | let x1 = -oneThird * x13 162 | let x2 = -oneThird * x23 163 | let x3 = -oneThird * x33 164 | 165 | return [x1, x2, x3] 166 | } 167 | } 168 | 169 | private func quartic() -> Multiset> { 170 | var a = coefficients[0] 171 | var b = coefficients[1] 172 | var c = coefficients[2] 173 | var d = coefficients[3] 174 | let e = coefficients[4] 175 | 176 | if a.isZero { 177 | return Polynomial(b, c, d, e).roots() 178 | } 179 | if e.isZero { 180 | return [Complex.zero()] + Polynomial(a, b, c, d).roots() 181 | } 182 | if b.isZero && d.isZero { // Biquadratic 183 | let squares = Polynomial(a, c, e).roots() 184 | return squares.flatMap { (square: Complex) -> Multiset> in 185 | let x = sqrt(square) 186 | return [x, -x] 187 | } 188 | } 189 | 190 | // Lodovico Ferrari's solution 191 | 192 | // Converting to a depressed quartic 193 | let a1 = b/a 194 | b = c/a 195 | c = d/a 196 | d = e/a 197 | a = a1 198 | 199 | let a2 = a*a 200 | let minus3a2 = -3.0*a2 201 | let ac64 = 64.0*a*c 202 | let a2b16 = 16.0*a2*b 203 | let aOn4 = a/4.0 204 | 205 | let p = b + minus3a2/8.0 206 | let ab4 = 4.0*a*b 207 | let q = (a2*a - ab4)/8.0 + c 208 | let r1 = minus3a2*a2 - ac64 + a2b16 209 | let r = r1/256.0 + d 210 | 211 | // Depressed quartic: u^4 + p*u^2 + q*u + r = 0 212 | 213 | if q.isZero { // Depressed quartic is biquadratic 214 | let squares = Polynomial(1.0, p, r).roots() 215 | return squares.flatMap { (square: Complex) -> Multiset> in 216 | let x = sqrt(square) 217 | return [x - aOn4, -x - aOn4] 218 | } 219 | } 220 | 221 | let p2 = p*p 222 | let q2On8 = q*q/8.0 223 | 224 | let cb = 2.5*p 225 | let cc = 2.0*p2 - r 226 | let cd = 0.5*p*(p2-r) - q2On8 227 | let yRoots = Polynomial(1.0, cb, cc, cd).roots() 228 | 229 | let y = yRoots[yRoots.startIndex] 230 | let y2 = 2.0*y 231 | let sqrtPPlus2y = sqrt(p + y2) 232 | precondition(sqrtPPlus2y.isZero == false, "Failed to properly handle the case of the depressed quartic being biquadratic") 233 | let p3 = 3.0*p 234 | let q2 = 2.0*q 235 | let fraction = q2/sqrtPPlus2y 236 | let p3Plus2y = p3 + y2 237 | let u1 = 0.5*(sqrtPPlus2y + sqrt(-(p3Plus2y + fraction))) 238 | let u2 = 0.5*(-sqrtPPlus2y + sqrt(-(p3Plus2y - fraction))) 239 | let u3 = 0.5*(sqrtPPlus2y - sqrt(-(p3Plus2y + fraction))) 240 | let u4 = 0.5*(-sqrtPPlus2y - sqrt(-(p3Plus2y - fraction))) 241 | return [ 242 | u1 - aOn4, 243 | u2 - aOn4, 244 | u3 - aOn4, 245 | u4 - aOn4 246 | ] 247 | } 248 | 249 | /// Implementation of the [Durand-Kerner-Weierstrass method](https://en.wikipedia.org/wiki/Durand%E2%80%93Kerner_method). 250 | private func durandKernerMethod() -> Multiset> { 251 | var coefficients = self.coefficients.map { Complex($0, Real(0)) } 252 | 253 | let one = Complex(Real(1), Real(0)) 254 | 255 | if coefficients[0] != one { 256 | coefficients = coefficients.map { coefficient in 257 | coefficient / coefficients[0] 258 | } 259 | } 260 | 261 | var a0 = [one] 262 | for _ in 1..] = [] 269 | for var i = 0; i < a0.count; i++ { 270 | var result = one 271 | for var j = 0; j < a0.count; j++ { 272 | if i != j { 273 | result = (a0[i] - a0[j]) * result 274 | } 275 | } 276 | roots.append(a0[i] - (eval(coefficients, a0[i]) / result)) 277 | } 278 | if done(a0, roots) { 279 | return Multiset(roots) 280 | } 281 | a0 = roots 282 | } 283 | 284 | return Multiset(a0) 285 | } 286 | 287 | private func eval(coefficients: [Complex], _ x: Complex) -> Complex { 288 | var result = coefficients[0] 289 | for i in 1..(aa: [Complex], _ bb: [Complex], _ epsilon: Real = Real.epsilon) -> Bool { 296 | for (a, b) in zip(aa, bb) { 297 | let delta = a - b 298 | if delta.abs > epsilon { 299 | return false 300 | } 301 | } 302 | return true 303 | } 304 | 305 | } 306 | 307 | // MARK: Equatable 308 | 309 | public func == (lhs: Polynomial, rhs: Polynomial) -> Bool { 310 | return lhs.coefficients == rhs.coefficients 311 | } 312 | 313 | -------------------------------------------------------------------------------- /SwiftMath/Quaternion.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Quaternions.swift 3 | // SwiftMath 4 | // 5 | // Created by Matteo Battaglio on 21/03/15. 6 | // Copyright (c) 2015 Matteo Battaglio. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct Quaternion : Equatable { 12 | 13 | public let re: Real 14 | public let im: Vector3 15 | 16 | public let isReal: Bool 17 | 18 | public init(_ re: Real, _ im: Vector3) { 19 | self.re = re 20 | self.im = im 21 | isReal = im == Vector3.zero() 22 | } 23 | 24 | public init(axis: Vector3, angle: Real) { 25 | assert(axis.length == 1.0, "axis is not a unit-length vector") 26 | let halfAngle = angle/2.0 27 | self.init(halfAngle.cos(), axis * halfAngle.sin()) 28 | } 29 | 30 | public static func id() -> Quaternion { 31 | return Quaternion(1.0, .zero()) 32 | } 33 | 34 | public var squareLength: Real { 35 | return re * re + im * im 36 | } 37 | 38 | public var length: Real { 39 | return norm 40 | } 41 | 42 | public var norm: Real { 43 | return squareLength.sqrt() 44 | } 45 | 46 | public func unit() -> Quaternion { 47 | return self / length 48 | } 49 | 50 | public func conj() -> Quaternion { 51 | return Quaternion(re, -im) 52 | } 53 | 54 | public func reciprocal() -> Quaternion { 55 | return self.conj() / squareLength 56 | } 57 | 58 | } 59 | 60 | public func == (lhs: Quaternion, rhs: Quaternion) -> Bool { 61 | return lhs.re == rhs.re && lhs.im == rhs.im 62 | } 63 | 64 | public func + (lhs: Quaternion, rhs: Quaternion) -> Quaternion { 65 | return Quaternion(lhs.re + rhs.re, lhs.im + rhs.im) 66 | } 67 | 68 | public func - (lhs: Quaternion, rhs: Quaternion) -> Quaternion { 69 | return Quaternion(lhs.re - rhs.re, lhs.im - rhs.im) 70 | } 71 | 72 | public func * (lhs: Real, rhs: Quaternion) -> Quaternion { 73 | return Quaternion(rhs.re * lhs, rhs.im * lhs) 74 | } 75 | 76 | public func * (lhs: Quaternion, rhs: Real) -> Quaternion { 77 | return rhs * lhs 78 | } 79 | 80 | public func / (quaternion: Quaternion, scalar: Real) -> Quaternion { 81 | return 1.0/scalar * quaternion 82 | } 83 | 84 | /// Dot product 85 | public func dotProduct(lhs: Quaternion, rhs: Quaternion) -> Real { 86 | return lhs.re * rhs.re + lhs.im * rhs.im 87 | } 88 | 89 | /// Dot product 90 | public func * (lhs: Quaternion, rhs: Quaternion) -> Real { 91 | return dotProduct(lhs, rhs: rhs) 92 | } 93 | 94 | public func multiply(lhs: Quaternion, rhs: Quaternion) -> Quaternion { 95 | let re = lhs.re * rhs.re - lhs.im * rhs.im 96 | let im = lhs.re * rhs.im + rhs.re * lhs.im + lhs.im × rhs.im 97 | return Quaternion(re, im) 98 | } 99 | 100 | infix operator × { associativity left precedence 150 } 101 | /// Multiplication 102 | public func × (lhs: Quaternion, rhs: Quaternion) -> Quaternion { 103 | return multiply(lhs, rhs: rhs) 104 | } 105 | 106 | extension Quaternion: CustomStringConvertible { 107 | 108 | public var description: String { 109 | return "(re: \(re), im: \(im))" 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /SwiftMath/RealType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RealType.swift 3 | // SwiftMath 4 | // 5 | // Created by Matteo Battaglio on 19/04/15. 6 | // Copyright (c) 2015 Dan Kogai, Matteo Battaglio. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol RealType: FloatingPointType, Hashable, FloatLiteralConvertible, SignedNumberType, CustomStringConvertible { 12 | 13 | init(_ value: Double) 14 | init(_ value: Float) 15 | 16 | // Built-in operators 17 | 18 | prefix func + (_: Self) -> Self 19 | prefix func - (_: Self) -> Self 20 | func + (_: Self, _: Self) -> Self 21 | func - (_: Self, _: Self) -> Self 22 | func * (_: Self, _: Self) -> Self 23 | func / (_: Self, _: Self) -> Self 24 | func += (inout _: Self, _: Self) 25 | func -= (inout _: Self, _: Self) 26 | func *= (inout _: Self, _: Self) 27 | func /= (inout _: Self, _: Self) 28 | 29 | // Methodized functions for protocol's sake 30 | 31 | var abs: Self { get } 32 | static var epsilon: Self { get } 33 | func cos() -> Self 34 | func exp() -> Self 35 | func log() -> Self 36 | func sin() -> Self 37 | func sqrt() -> Self 38 | func hypot(_: Self) -> Self 39 | func atan2(_: Self) -> Self 40 | func pow(_: Self) -> Self 41 | 42 | // Constants 43 | 44 | static var PI: Self { get } 45 | static var π: Self { get } 46 | static var E: Self { get } 47 | static var e: Self { get } 48 | static var LN2: Self { get } 49 | static var LOG2E: Self { get } 50 | static var LN10: Self { get } 51 | static var LOG10E: Self { get } 52 | static var SQRT2: Self { get } 53 | static var SQRT1_2: Self { get } 54 | } 55 | 56 | // MARK: - Constants 57 | 58 | extension RealType { 59 | public var abs: Self { return Swift.abs(self) } 60 | 61 | public static var PI: Self { return 3.14159265358979323846264338327950288419716939937510 } 62 | public static var π: Self { return PI } 63 | public static var E: Self { return 2.718281828459045235360287471352662497757247093699 } 64 | public static var e: Self { return E } 65 | public static var LN2: Self { return 0.6931471805599453094172321214581765680755001343602552 } 66 | public static var LOG2E: Self { return 1.0 / LN2 } 67 | public static var LN10: Self { return 2.3025850929940456840179914546843642076011014886287729 } 68 | public static var LOG10E: Self { return 1.0 / LN10 } 69 | public static var SQRT2: Self { return 1.4142135623730950488016887242096980785696718753769480 } 70 | public static var SQRT1_2: Self { return 1.0 / SQRT2 } 71 | } 72 | 73 | // MARK: - Double extension to conform to RealType 74 | 75 | // Double is default since floating-point literals are Double by default 76 | extension Double: RealType { 77 | 78 | public func cos() -> Double { return Foundation.cos(self) } 79 | public func exp() -> Double { return Foundation.exp(self) } 80 | public func log() -> Double { return Foundation.log(self) } 81 | public func sin() -> Double { return Foundation.sin(self) } 82 | public func sqrt() -> Double { return Foundation.sqrt(self) } 83 | public func atan2(y: Double) -> Double { return Foundation.atan2(self, y) } 84 | public func hypot(y: Double) -> Double { return Foundation.hypot(self, y) } 85 | public func pow(y: Double) -> Double { return Foundation.pow(self, y) } 86 | 87 | public static let epsilon = 0x1p-52 88 | } 89 | 90 | // MARK: - Float extension to conform to RealType 91 | 92 | // But when explicitly typed you can use Float 93 | extension Float: RealType { 94 | public func cos() -> Float { return Foundation.cos(self) } 95 | public func exp() -> Float { return Foundation.exp(self) } 96 | public func log() -> Float { return Foundation.log(self) } 97 | public func sin() -> Float { return Foundation.sin(self) } 98 | public func sqrt() -> Float { return Foundation.sqrt(self) } 99 | public func hypot(y: Float) -> Float { return Foundation.hypot(self, y) } 100 | public func atan2(y: Float) -> Float { return Foundation.atan2(self, y) } 101 | public func pow(y: Float) -> Float { return Foundation.pow(self, y) } 102 | 103 | public static let epsilon: Float = 0x1p-23 104 | } 105 | 106 | // 107 | // approximate comparison 108 | // 109 | public func =~ (lhs: T, rhs: T) -> Bool { 110 | if lhs == rhs { 111 | return true 112 | } 113 | return (rhs - lhs).abs < T.epsilon 114 | // let epsilon = sizeof(T) < 8 ? 0x1p-23 : 0x1p-52 115 | // return t.abs <= T(2) * T(epsilon) 116 | } 117 | 118 | public func !~ (lhs: T, rhs: T) -> Bool { 119 | return !(lhs =~ rhs) 120 | } 121 | 122 | // MARK: CustomStringConvertible 123 | 124 | extension RealType { 125 | 126 | var description: String { 127 | if self is Double { 128 | return (self as! Double).description 129 | } else { 130 | return (self as! Float).description 131 | } 132 | } 133 | 134 | } 135 | -------------------------------------------------------------------------------- /SwiftMath/SquareMatrix.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SquareMatrix.swift 3 | // SwiftMath 4 | // 5 | // Created by Matteo Battaglio on 13/08/15. 6 | // Copyright © 2015 Matteo Battaglio. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | //public struct SquareMatrix: SquareMatrixType { 12 | // 13 | //} -------------------------------------------------------------------------------- /SwiftMath/SquareMatrixType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MatrixType.swift 3 | // SwiftMath 4 | // 5 | // Created by Matteo Battaglio on 25/07/15. 6 | // Copyright © 2015 Matteo Battaglio. All rights reserved. 7 | // 8 | 9 | protocol SquareMatrixType: MatrixType { 10 | 11 | static func identity(rowCount: Int) -> Self 12 | 13 | var determinant: Element { get } 14 | 15 | func transpose() -> Self 16 | 17 | func cofactor() -> Self 18 | 19 | func adjugate() -> Self 20 | 21 | func inverse() -> Self? 22 | 23 | var isInvertible: Bool { get } 24 | 25 | var isOrthogonal: Bool { get } 26 | 27 | } -------------------------------------------------------------------------------- /SwiftMath/Surge/Arithmetic.swift: -------------------------------------------------------------------------------- 1 | // Arithmetic.swift 2 | // 3 | // Copyright (c) 2014–2015 Mattt Thompson (http://mattt.me) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | import Accelerate 24 | 25 | // MARK: Sum 26 | 27 | func sum(x: [Float]) -> Float { 28 | var result: Float = 0.0 29 | vDSP_sve(x, 1, &result, vDSP_Length(x.count)) 30 | 31 | return result 32 | } 33 | 34 | func sum(x: [Double]) -> Double { 35 | var result: Double = 0.0 36 | vDSP_sveD(x, 1, &result, vDSP_Length(x.count)) 37 | 38 | return result 39 | } 40 | 41 | // MARK: Sum of Absolute Values 42 | 43 | func asum(x: [Float]) -> Float { 44 | return cblas_sasum(Int32(x.count), x, 1) 45 | } 46 | 47 | func asum(x: [Double]) -> Double { 48 | return cblas_dasum(Int32(x.count), x, 1) 49 | } 50 | 51 | // MARK: Maximum 52 | 53 | func max(x: [Float]) -> Float { 54 | var result: Float = 0.0 55 | vDSP_maxv(x, 1, &result, vDSP_Length(x.count)) 56 | 57 | return result 58 | } 59 | 60 | func max(x: [Double]) -> Double { 61 | var result: Double = 0.0 62 | vDSP_maxvD(x, 1, &result, vDSP_Length(x.count)) 63 | 64 | return result 65 | } 66 | 67 | // MARK: Minimum 68 | 69 | func min(x: [Float]) -> Float { 70 | var result: Float = 0.0 71 | vDSP_minv(x, 1, &result, vDSP_Length(x.count)) 72 | 73 | return result 74 | } 75 | 76 | func min(x: [Double]) -> Double { 77 | var result: Double = 0.0 78 | vDSP_minvD(x, 1, &result, vDSP_Length(x.count)) 79 | 80 | return result 81 | } 82 | 83 | // MARK: Mean 84 | 85 | func mean(x: [Float]) -> Float { 86 | var result: Float = 0.0 87 | vDSP_meanv(x, 1, &result, vDSP_Length(x.count)) 88 | 89 | return result 90 | } 91 | 92 | func mean(x: [Double]) -> Double { 93 | var result: Double = 0.0 94 | vDSP_meanvD(x, 1, &result, vDSP_Length(x.count)) 95 | 96 | return result 97 | } 98 | 99 | // MARK: Mean Magnitude 100 | 101 | func meamg(x: [Float]) -> Float { 102 | var result: Float = 0.0 103 | vDSP_meamgv(x, 1, &result, vDSP_Length(x.count)) 104 | 105 | return result 106 | } 107 | 108 | func meamg(x: [Double]) -> Double { 109 | var result: Double = 0.0 110 | vDSP_meamgvD(x, 1, &result, vDSP_Length(x.count)) 111 | 112 | return result 113 | } 114 | 115 | // MARK: Mean Square Value 116 | 117 | func measq(x: [Float]) -> Float { 118 | var result: Float = 0.0 119 | vDSP_measqv(x, 1, &result, vDSP_Length(x.count)) 120 | 121 | return result 122 | } 123 | 124 | func measq(x: [Double]) -> Double { 125 | var result: Double = 0.0 126 | vDSP_measqvD(x, 1, &result, vDSP_Length(x.count)) 127 | 128 | return result 129 | } 130 | 131 | // MARK: Square Root 132 | 133 | func sqrt(x: [Float]) -> [Float] { 134 | var results = [Float](count: x.count, repeatedValue: 0.0) 135 | vvsqrtf(&results, x, [Int32(x.count)]) 136 | 137 | return results 138 | } 139 | 140 | func sqrt(x: [Double]) -> [Double] { 141 | var results = [Double](count: x.count, repeatedValue: 0.0) 142 | vvsqrt(&results, x, [Int32(x.count)]) 143 | 144 | return results 145 | } 146 | 147 | // MARK: Add 148 | 149 | public func add(x: [Real], _ y: [Real]) -> [Real] { 150 | return analysis(x, y, ifFloat: add, ifDouble: add) 151 | } 152 | 153 | func add(x: [Float], _ y: [Float]) -> [Float] { 154 | var results = [Float](y) 155 | cblas_saxpy(Int32(x.count), 1.0, x, 1, &results, 1) 156 | 157 | return results 158 | } 159 | 160 | func add(x: [Double], _ y: [Double]) -> [Double] { 161 | var results = [Double](y) 162 | cblas_daxpy(Int32(x.count), 1.0, x, 1, &results, 1) 163 | 164 | return results 165 | } 166 | 167 | // MARK: Multiply 168 | 169 | public func multiply(x: [Real], _ y: [Real]) -> [Real] { 170 | return analysis(x, y, ifFloat: mul, ifDouble: mul) 171 | } 172 | 173 | func mul(x: [Float], _ y: [Float]) -> [Float] { 174 | var results = [Float](count: x.count, repeatedValue: 0.0) 175 | vDSP_vmul(x, 1, y, 1, &results, 1, vDSP_Length(x.count)) 176 | 177 | return results 178 | } 179 | 180 | func mul(x: [Double], _ y: [Double]) -> [Double] { 181 | var results = [Double](count: x.count, repeatedValue: 0.0) 182 | vDSP_vmulD(x, 1, y, 1, &results, 1, vDSP_Length(x.count)) 183 | 184 | return results 185 | } 186 | 187 | // MARK: Divide 188 | 189 | public func divide(x: [Real], _ y: [Real]) -> [Real] { 190 | return analysis(x, y, ifFloat: div, ifDouble: div) 191 | } 192 | 193 | func div(x: [Float], _ y: [Float]) -> [Float] { 194 | var results = [Float](count: x.count, repeatedValue: 0.0) 195 | vvdivf(&results, x, y, [Int32(x.count)]) 196 | 197 | return results 198 | } 199 | 200 | func div(x: [Double], _ y: [Double]) -> [Double] { 201 | var results = [Double](count: x.count, repeatedValue: 0.0) 202 | vvdiv(&results, x, y, [Int32(x.count)]) 203 | 204 | return results 205 | } 206 | 207 | // MARK: Modulo 208 | 209 | public func modulo(x: [Real], _ y: [Real]) -> [Real] { 210 | return analysis(x, y, ifFloat: mod, ifDouble: mod) 211 | } 212 | 213 | func mod(x: [Float], _ y: [Float]) -> [Float] { 214 | var results = [Float](count: x.count, repeatedValue: 0.0) 215 | vvfmodf(&results, x, y, [Int32(x.count)]) 216 | 217 | return results 218 | } 219 | 220 | func mod(x: [Double], _ y: [Double]) -> [Double] { 221 | var results = [Double](count: x.count, repeatedValue: 0.0) 222 | vvfmod(&results, x, y, [Int32(x.count)]) 223 | 224 | return results 225 | } 226 | 227 | // MARK: Remainder 228 | 229 | public func remainder(x: [Real], _ y: [Real]) -> [Real] { 230 | return analysis(x, y, ifFloat: remainder, ifDouble: remainder) 231 | } 232 | 233 | func remainder(x: [Float], _ y: [Float]) -> [Float] { 234 | var results = [Float](count: x.count, repeatedValue: 0.0) 235 | vvremainderf(&results, x, y, [Int32(x.count)]) 236 | 237 | return results 238 | } 239 | 240 | func remainder(x: [Double], _ y: [Double]) -> [Double] { 241 | var results = [Double](count: x.count, repeatedValue: 0.0) 242 | vvremainder(&results, x, y, [Int32(x.count)]) 243 | 244 | return results 245 | } 246 | 247 | // MARK: Dot Product 248 | 249 | public func dotProduct(x: [Real], _ y: [Real]) -> Real { 250 | precondition(x.count == y.count, "Vectors must have equal count") 251 | return analysis(x, y, ifFloat: dot, ifDouble: dot) 252 | } 253 | 254 | func dot(x: [Float], _ y: [Float]) -> Float { 255 | precondition(x.count == y.count, "Vectors must have equal count") 256 | 257 | var result: Float = 0.0 258 | vDSP_dotpr(x, 1, y, 1, &result, vDSP_Length(x.count)) 259 | 260 | return result 261 | } 262 | 263 | 264 | func dot(x: [Double], _ y: [Double]) -> Double { 265 | precondition(x.count == y.count, "Vectors must have equal count") 266 | 267 | var result: Double = 0.0 268 | vDSP_dotprD(x, 1, y, 1, &result, vDSP_Length(x.count)) 269 | 270 | return result 271 | } 272 | 273 | // MARK: - Operators 274 | 275 | public func + (lhs: [Real], rhs: [Real]) -> [Real] { 276 | return add(lhs, rhs) 277 | } 278 | 279 | public func + (lhs: [Real], rhs: Real) -> [Real] { 280 | return add(lhs, [Real](count: lhs.count, repeatedValue: rhs)) 281 | } 282 | 283 | public func / (lhs: [Real], rhs: [Real]) -> [Real] { 284 | return divide(lhs, rhs) 285 | } 286 | 287 | public func / (lhs: [Real], rhs: Real) -> [Real] { 288 | return divide(lhs, [Real](count: lhs.count, repeatedValue: rhs)) 289 | } 290 | 291 | public func * (lhs: [Real], rhs: [Real]) -> [Real] { 292 | return multiply(lhs, rhs) 293 | } 294 | 295 | public func * (lhs: [Real], rhs: Real) -> [Real] { 296 | return multiply(lhs, [Real](count: lhs.count, repeatedValue: rhs)) 297 | } 298 | 299 | public func % (lhs: [Real], rhs: [Real]) -> [Real] { 300 | return modulo(lhs, rhs) 301 | } 302 | 303 | public func % (lhs: [Real], rhs: Real) -> [Real] { 304 | return modulo(lhs, [Real](count: lhs.count, repeatedValue: rhs)) 305 | } 306 | 307 | infix operator • { associativity left precedence 150 } 308 | public func • (lhs: [Real], rhs: [Real]) -> Real { 309 | return dotProduct(lhs, rhs) 310 | } 311 | -------------------------------------------------------------------------------- /SwiftMath/Surge/Auxiliary.swift: -------------------------------------------------------------------------------- 1 | // Auxilliary.swift 2 | // 3 | // Copyright (c) 2014–2015 Mattt Thompson (http://mattt.me) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | import Accelerate 24 | 25 | // MARK: Absolute Value 26 | 27 | func abs(x: [Double]) -> [Double] { 28 | var results = [Double](count: x.count, repeatedValue: 0.0) 29 | vvfabs(&results, x, [Int32(x.count)]) 30 | 31 | return results 32 | } 33 | 34 | func abs(x: [Float]) -> [Float] { 35 | var results = [Float](count: x.count, repeatedValue: 0.0) 36 | vvfabsf(&results, x, [Int32(x.count)]) 37 | 38 | return results 39 | } 40 | 41 | // MARK: Ceiling 42 | 43 | func ceil(x: [Float]) -> [Float] { 44 | var results = [Float](count: x.count, repeatedValue: 0.0) 45 | vvceilf(&results, x, [Int32(x.count)]) 46 | 47 | return results 48 | } 49 | 50 | func ceil(x: [Double]) -> [Double] { 51 | var results = [Double](count: x.count, repeatedValue: 0.0) 52 | vvceil(&results, x, [Int32(x.count)]) 53 | 54 | return results 55 | } 56 | 57 | // MARK: Clip 58 | 59 | func clip(x: [Float], _ low: Float, _ high: Float) -> [Float] { 60 | var results = [Float](count: x.count, repeatedValue: 0.0), y = low, z = high 61 | vDSP_vclip(x, 1, &y, &z, &results, 1, vDSP_Length(x.count)) 62 | 63 | return results 64 | } 65 | 66 | func clip(x: [Double], _ low: Double, _ high: Double) -> [Double] { 67 | var results = [Double](count: x.count, repeatedValue: 0.0), y = low, z = high 68 | vDSP_vclipD(x, 1, &y, &z, &results, 1, vDSP_Length(x.count)) 69 | 70 | return results 71 | } 72 | 73 | // MARK: Copy Sign 74 | 75 | public func copysign(sign: [Real], _ magnitude: [Real]) -> [Real] { 76 | return analysis(sign, magnitude, ifFloat: copysign, ifDouble: copysign) 77 | } 78 | 79 | func copysign(sign: [Float], _ magnitude: [Float]) -> [Float] { 80 | var results = [Float](count: sign.count, repeatedValue: 0.0) 81 | vvcopysignf(&results, magnitude, sign, [Int32(sign.count)]) 82 | 83 | return results 84 | } 85 | 86 | func copysign(sign: [Double], _ magnitude: [Double]) -> [Double] { 87 | var results = [Double](count: sign.count, repeatedValue: 0.0) 88 | vvcopysign(&results, magnitude, sign, [Int32(sign.count)]) 89 | 90 | return results 91 | } 92 | 93 | // MARK: Floor 94 | 95 | func floor(x: [Float]) -> [Float] { 96 | var results = [Float](count: x.count, repeatedValue: 0.0) 97 | vvfloorf(&results, x, [Int32(x.count)]) 98 | 99 | return results 100 | } 101 | 102 | func floor(x: [Double]) -> [Double] { 103 | var results = [Double](count: x.count, repeatedValue: 0.0) 104 | vvfloor(&results, x, [Int32(x.count)]) 105 | 106 | return results 107 | } 108 | 109 | // MARK: Negate 110 | 111 | func neg(x: [Float]) -> [Float] { 112 | var results = [Float](count: x.count, repeatedValue: 0.0) 113 | vDSP_vneg(x, 1, &results, 1, vDSP_Length(x.count)) 114 | 115 | return results 116 | } 117 | 118 | func neg(x: [Double]) -> [Double] { 119 | var results = [Double](count: x.count, repeatedValue: 0.0) 120 | vDSP_vnegD(x, 1, &results, 1, vDSP_Length(x.count)) 121 | 122 | return results 123 | } 124 | 125 | // MARK: Reciprocal 126 | 127 | func rec(x: [Float]) -> [Float] { 128 | var results = [Float](count: x.count, repeatedValue: 0.0) 129 | vvrecf(&results, x, [Int32(x.count)]) 130 | 131 | return results 132 | } 133 | 134 | func rec(x: [Double]) -> [Double] { 135 | var results = [Double](count: x.count, repeatedValue: 0.0) 136 | vvrec(&results, x, [Int32(x.count)]) 137 | 138 | return results 139 | } 140 | 141 | // MARK: Round 142 | 143 | func round(x: [Float]) -> [Float] { 144 | var results = [Float](count: x.count, repeatedValue: 0.0) 145 | vvnintf(&results, x, [Int32(x.count)]) 146 | 147 | return results 148 | } 149 | 150 | func round(x: [Double]) -> [Double] { 151 | var results = [Double](count: x.count, repeatedValue: 0.0) 152 | vvnint(&results, x, [Int32(x.count)]) 153 | 154 | return results 155 | } 156 | 157 | // MARK: Threshold 158 | 159 | func threshold(x: [Float], _ low: Float) -> [Float] { 160 | var results = [Float](count: x.count, repeatedValue: 0.0), y = low 161 | vDSP_vthr(x, 1, &y, &results, 1, vDSP_Length(x.count)) 162 | 163 | return results 164 | } 165 | 166 | func threshold(x: [Double], _ low: Double) -> [Double] { 167 | var results = [Double](count: x.count, repeatedValue: 0.0), y = low 168 | vDSP_vthrD(x, 1, &y, &results, 1, vDSP_Length(x.count)) 169 | 170 | return results 171 | } 172 | 173 | // MARK: Truncate 174 | 175 | func trunc(x: [Float]) -> [Float] { 176 | var results = [Float](count: x.count, repeatedValue: 0.0) 177 | vvintf(&results, x, [Int32(x.count)]) 178 | 179 | return results 180 | } 181 | 182 | func trunc(x: [Double]) -> [Double] { 183 | var results = [Double](count: x.count, repeatedValue: 0.0) 184 | vvint(&results, x, [Int32(x.count)]) 185 | 186 | return results 187 | } 188 | -------------------------------------------------------------------------------- /SwiftMath/Surge/Exponential.swift: -------------------------------------------------------------------------------- 1 | // Exponential.swift 2 | // 3 | // Copyright (c) 2014–2015 Mattt Thompson (http://mattt.me) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | import Accelerate 24 | 25 | // MARK: Exponentiation 26 | 27 | func exp(x: [Float]) -> [Float] { 28 | var results = [Float](count: x.count, repeatedValue: 0.0) 29 | vvexpf(&results, x, [Int32(x.count)]) 30 | 31 | return results 32 | } 33 | 34 | func exp(x: [Double]) -> [Double] { 35 | var results = [Double](count: x.count, repeatedValue: 0.0) 36 | vvexp(&results, x, [Int32(x.count)]) 37 | 38 | return results 39 | } 40 | 41 | // MARK: Square Exponentiation 42 | 43 | func exp2(x: [Float]) -> [Float] { 44 | var results = [Float](count: x.count, repeatedValue: 0.0) 45 | vvexp2f(&results, x, [Int32(x.count)]) 46 | 47 | return results 48 | } 49 | 50 | func exp2(x: [Double]) -> [Double] { 51 | var results = [Double](count: x.count, repeatedValue: 0.0) 52 | vvexp2(&results, x, [Int32(x.count)]) 53 | 54 | return results 55 | } 56 | 57 | // MARK: Natural Logarithm 58 | 59 | func log(x: [Float]) -> [Float] { 60 | var results = [Float](x) 61 | vvlogf(&results, x, [Int32(x.count)]) 62 | 63 | return results 64 | } 65 | 66 | func log(x: [Double]) -> [Double] { 67 | var results = [Double](x) 68 | vvlog(&results, x, [Int32(x.count)]) 69 | 70 | return results 71 | } 72 | 73 | // MARK: Base-2 Logarithm 74 | 75 | func log2(x: [Float]) -> [Float] { 76 | var results = [Float](x) 77 | vvlog2f(&results, x, [Int32(x.count)]) 78 | 79 | return results 80 | } 81 | 82 | func log2(x: [Double]) -> [Double] { 83 | var results = [Double](x) 84 | vvlog2(&results, x, [Int32(x.count)]) 85 | 86 | return results 87 | } 88 | 89 | // MARK: Base-10 Logarithm 90 | 91 | func log10(x: [Float]) -> [Float] { 92 | var results = [Float](x) 93 | vvlog10f(&results, x, [Int32(x.count)]) 94 | 95 | return results 96 | } 97 | 98 | func log10(x: [Double]) -> [Double] { 99 | var results = [Double](x) 100 | vvlog10(&results, x, [Int32(x.count)]) 101 | 102 | return results 103 | } 104 | 105 | // MARK: Logarithmic Exponentiation 106 | 107 | func logb(x: [Float]) -> [Float] { 108 | var results = [Float](x) 109 | vvlogbf(&results, x, [Int32(x.count)]) 110 | 111 | return results 112 | } 113 | 114 | func logb(x: [Double]) -> [Double] { 115 | var results = [Double](x) 116 | vvlogb(&results, x, [Int32(x.count)]) 117 | 118 | return results 119 | } 120 | -------------------------------------------------------------------------------- /SwiftMath/Surge/FFT.swift: -------------------------------------------------------------------------------- 1 | // FFT.swift 2 | // 3 | // Copyright (c) 2014–2015 Mattt Thompson (http://mattt.me) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | import Accelerate 24 | 25 | // MARK: Fast Fourier Transform 26 | 27 | func fft(input: [Float]) -> [Float] { 28 | var real = [Float](input) 29 | var imaginary = [Float](count: input.count, repeatedValue: 0.0) 30 | var splitComplex = DSPSplitComplex(realp: &real, imagp: &imaginary) 31 | 32 | let length = vDSP_Length(floor(log2(Float(input.count)))) 33 | let radix = FFTRadix(kFFTRadix2) 34 | let weights = vDSP_create_fftsetup(length, radix) 35 | vDSP_fft_zip(weights, &splitComplex, 1, length, FFTDirection(FFT_FORWARD)) 36 | 37 | var magnitudes = [Float](count: input.count, repeatedValue: 0.0) 38 | vDSP_zvmags(&splitComplex, 1, &magnitudes, 1, vDSP_Length(input.count)) 39 | 40 | var normalizedMagnitudes = [Float](count: input.count, repeatedValue: 0.0) 41 | vDSP_vsmul(sqrt(magnitudes), 1, [2.0 / Float(input.count)], &normalizedMagnitudes, 1, vDSP_Length(input.count)) 42 | 43 | vDSP_destroy_fftsetup(weights) 44 | 45 | return normalizedMagnitudes 46 | } 47 | 48 | func fft(input: [Double]) -> [Double] { 49 | var real = [Double](input) 50 | var imaginary = [Double](count: input.count, repeatedValue: 0.0) 51 | var splitComplex = DSPDoubleSplitComplex(realp: &real, imagp: &imaginary) 52 | 53 | let length = vDSP_Length(floor(log2(Float(input.count)))) 54 | let radix = FFTRadix(kFFTRadix2) 55 | let weights = vDSP_create_fftsetupD(length, radix) 56 | vDSP_fft_zipD(weights, &splitComplex, 1, length, FFTDirection(FFT_FORWARD)) 57 | 58 | var magnitudes = [Double](count: input.count, repeatedValue: 0.0) 59 | vDSP_zvmagsD(&splitComplex, 1, &magnitudes, 1, vDSP_Length(input.count)) 60 | 61 | var normalizedMagnitudes = [Double](count: input.count, repeatedValue: 0.0) 62 | vDSP_vsmulD(sqrt(magnitudes), 1, [2.0 / Double(input.count)], &normalizedMagnitudes, 1, vDSP_Length(input.count)) 63 | 64 | vDSP_destroy_fftsetupD(weights) 65 | 66 | return normalizedMagnitudes 67 | } 68 | -------------------------------------------------------------------------------- /SwiftMath/Surge/Hyperbolic.swift: -------------------------------------------------------------------------------- 1 | // Hyperbolic.swift 2 | // 3 | // Copyright (c) 2014–2015 Mattt Thompson (http://mattt.me) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | import Accelerate 24 | 25 | // MARK: Hyperbolic Sine 26 | 27 | public func sinh(x: [Float]) -> [Float] { 28 | var results = [Float](count: x.count, repeatedValue: 0.0) 29 | vvsinhf(&results, x, [Int32(x.count)]) 30 | 31 | return results 32 | } 33 | 34 | public func sinh(x: [Double]) -> [Double] { 35 | var results = [Double](count: x.count, repeatedValue: 0.0) 36 | vvsinh(&results, x, [Int32(x.count)]) 37 | 38 | return results 39 | } 40 | 41 | // MARK: Hyperbolic Cosine 42 | 43 | public func cosh(x: [Float]) -> [Float] { 44 | var results = [Float](count: x.count, repeatedValue: 0.0) 45 | vvcoshf(&results, x, [Int32(x.count)]) 46 | 47 | return results 48 | } 49 | 50 | public func cosh(x: [Double]) -> [Double] { 51 | var results = [Double](count: x.count, repeatedValue: 0.0) 52 | vvcosh(&results, x, [Int32(x.count)]) 53 | 54 | return results 55 | } 56 | 57 | // MARK: Hyperbolic Tangent 58 | 59 | public func tanh(x: [Float]) -> [Float] { 60 | var results = [Float](count: x.count, repeatedValue: 0.0) 61 | vvtanhf(&results, x, [Int32(x.count)]) 62 | 63 | return results 64 | } 65 | 66 | public func tanh(x: [Double]) -> [Double] { 67 | var results = [Double](count: x.count, repeatedValue: 0.0) 68 | vvtanh(&results, x, [Int32(x.count)]) 69 | 70 | return results 71 | } 72 | 73 | // MARK: Inverse Hyperbolic Sine 74 | 75 | public func asinh(x: [Float]) -> [Float] { 76 | var results = [Float](count: x.count, repeatedValue: 0.0) 77 | vvasinhf(&results, x, [Int32(x.count)]) 78 | 79 | return results 80 | } 81 | 82 | public func asinh(x: [Double]) -> [Double] { 83 | var results = [Double](count: x.count, repeatedValue: 0.0) 84 | vvasinh(&results, x, [Int32(x.count)]) 85 | 86 | return results 87 | } 88 | 89 | // MARK: Inverse Hyperbolic Cosine 90 | 91 | public func acosh(x: [Float]) -> [Float] { 92 | var results = [Float](count: x.count, repeatedValue: 0.0) 93 | vvacoshf(&results, x, [Int32(x.count)]) 94 | 95 | return results 96 | } 97 | 98 | public func acosh(x: [Double]) -> [Double] { 99 | var results = [Double](count: x.count, repeatedValue: 0.0) 100 | vvacosh(&results, x, [Int32(x.count)]) 101 | 102 | return results 103 | } 104 | 105 | // MARK: Inverse Hyperbolic Tangent 106 | 107 | public func atanh(x: [Float]) -> [Float] { 108 | var results = [Float](count: x.count, repeatedValue: 0.0) 109 | vvatanhf(&results, x, [Int32(x.count)]) 110 | 111 | return results 112 | } 113 | 114 | public func atanh(x: [Double]) -> [Double] { 115 | var results = [Double](count: x.count, repeatedValue: 0.0) 116 | vvatanh(&results, x, [Int32(x.count)]) 117 | 118 | return results 119 | } 120 | -------------------------------------------------------------------------------- /SwiftMath/Surge/Matrix.swift: -------------------------------------------------------------------------------- 1 | // Hyperbolic.swift 2 | // 3 | // Copyright (c) 2014–2015 Mattt Thompson (http://mattt.me) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | import Accelerate 24 | 25 | public struct Matrix: MatrixType { 26 | 27 | public var grid: [Real] = [] 28 | public let order: (rows: Int, columns: Int) 29 | 30 | public var prova: Real { 31 | return Real(1) 32 | } 33 | 34 | public init(rows: Int, columns: Int, repeatedValue: Real) { 35 | order = (rows, columns) 36 | grid = [Real](count: rows * columns, repeatedValue: repeatedValue) 37 | } 38 | 39 | public init(_ rows: [[Real]]) { 40 | let m: Int = rows.count 41 | let n: Int = rows[0].count 42 | order = (m, n) 43 | grid.reserveCapacity(m*n) 44 | for row in rows { 45 | grid += row 46 | // grid.replaceRange((i*n)..<(i*n+m), with: row) 47 | } 48 | } 49 | 50 | public subscript(row: Int, column: Int) -> Real { 51 | get { 52 | assert(indexIsValidForRow(row, column: column)) 53 | return grid[(row * order.columns) + column] 54 | } 55 | set { 56 | assert(indexIsValidForRow(row, column: column)) 57 | grid[(row * order.columns) + column] = newValue 58 | } 59 | } 60 | 61 | private func indexIsValidForRow(row: Int, column: Int) -> Bool { 62 | return row >= 0 && row < order.rows && column >= 0 && column < order.columns 63 | } 64 | } 65 | 66 | // MARK: - CustomStringConvertible 67 | 68 | extension Matrix: CustomStringConvertible { 69 | public var description: String { 70 | var description = "" 71 | 72 | for i in 0.. AnyGenerator> { 98 | let endIndex = order.rows * order.columns 99 | var nextRowStartIndex = 0 100 | 101 | return anyGenerator { 102 | if nextRowStartIndex == endIndex { 103 | return nil 104 | } 105 | 106 | let currentRowStartIndex = nextRowStartIndex 107 | nextRowStartIndex += self.order.columns 108 | 109 | return self.grid[currentRowStartIndex..) -> Int { 118 | var results = x 119 | 120 | var nr = __CLPK_integer(x.order.rows) 121 | var nc = __CLPK_integer(x.order.columns) 122 | var lwork = __CLPK_integer(10*max(nr, nc)) 123 | var work = [__CLPK_real](count: Int(lwork), repeatedValue: 0.0) 124 | var error: __CLPK_integer = 0 125 | let lds = max(nr, nc) 126 | var s = [__CLPK_real](count: Int(lds), repeatedValue: 0.0) 127 | var u = [__CLPK_real](count: Int(nr * nr), repeatedValue: 0.0) 128 | var vt = [__CLPK_real](count: Int(nc), repeatedValue: 0.0) 129 | 130 | var jobu: Int8 = 78 // 'N' 131 | var jobvt: Int8 = 78 // 'N' 132 | 133 | sgesvd_(&jobu, &jobvt, &nr, &nc, &(results.grid), &nc, &s, &u, &nr, &vt, &nc, &work, &lwork, &error) 134 | 135 | print(s) 136 | 137 | let epsilon: Float = 1e-4 138 | return s.lazy.filter { $0 > epsilon }.count 139 | } 140 | 141 | public func add(x: Matrix, y: Matrix) -> Matrix { 142 | precondition(x.order.rows == y.order.rows && x.order.columns == y.order.columns, "Matrix dimensions not compatible with addition") 143 | 144 | var results = y 145 | cblas_saxpy(Int32(x.grid.count), 1.0, x.grid, 1, &(results.grid), 1) 146 | 147 | return results 148 | } 149 | 150 | public func add(x: Matrix, y: Matrix) -> Matrix { 151 | precondition(x.order.rows == y.order.rows && x.order.columns == y.order.columns, "Matrix dimensions not compatible with addition") 152 | 153 | var results = y 154 | cblas_daxpy(Int32(x.grid.count), 1.0, x.grid, 1, &(results.grid), 1) 155 | 156 | return results 157 | } 158 | 159 | public func mul(alpha: Float, x: Matrix) -> Matrix { 160 | var results = x 161 | cblas_sscal(Int32(x.grid.count), alpha, &(results.grid), 1) 162 | 163 | return results 164 | } 165 | 166 | public func mul(alpha: Double, x: Matrix) -> Matrix { 167 | var results = x 168 | cblas_dscal(Int32(x.grid.count), alpha, &(results.grid), 1) 169 | 170 | return results 171 | } 172 | 173 | public func mul(x: Matrix, y: Matrix) -> Matrix { 174 | precondition(x.order.columns == y.order.rows, "Matrix dimensions not compatible with multiplication") 175 | 176 | var results = Matrix(rows: x.order.rows, columns: y.order.columns, repeatedValue: 0.0) 177 | cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, Int32(x.order.rows), Int32(y.order.columns), Int32(x.order.columns), 1.0, x.grid, Int32(x.order.columns), y.grid, Int32(y.order.columns), 0.0, &(results.grid), Int32(results.order.columns)) 178 | 179 | return results 180 | } 181 | 182 | public func mul(x: Matrix, y: Matrix) -> Matrix { 183 | precondition(x.order.columns == y.order.rows, "Matrix dimensions not compatible with multiplication") 184 | 185 | var results = Matrix(rows: x.order.rows, columns: y.order.columns, repeatedValue: 0.0) 186 | cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, Int32(x.order.rows), Int32(y.order.columns), Int32(x.order.columns), 1.0, x.grid, Int32(x.order.columns), y.grid, Int32(y.order.columns), 0.0, &(results.grid), Int32(results.order.columns)) 187 | 188 | return results 189 | } 190 | 191 | public func inv(x: Matrix) -> Matrix { 192 | precondition(x.order.rows == x.order.columns, "Matrix must be square") 193 | 194 | var results = x 195 | 196 | var ipiv = [__CLPK_integer](count: x.order.rows * x.order.rows, repeatedValue: 0) 197 | var lwork = __CLPK_integer(x.order.columns * x.order.columns) 198 | var work = [CFloat](count: Int(lwork), repeatedValue: 0.0) 199 | var error: __CLPK_integer = 0 200 | var nc = __CLPK_integer(x.order.columns) 201 | 202 | sgetrf_(&nc, &nc, &(results.grid), &nc, &ipiv, &error) 203 | sgetri_(&nc, &(results.grid), &nc, &ipiv, &work, &lwork, &error) 204 | 205 | assert(error == 0, "Matrix not invertible") 206 | 207 | return results 208 | } 209 | 210 | public func inv(x: Matrix) -> Matrix { 211 | precondition(x.order.rows == x.order.columns, "Matrix must be square") 212 | 213 | var results = x 214 | 215 | var ipiv = [__CLPK_integer](count: x.order.rows * x.order.rows, repeatedValue: 0) 216 | var lwork = __CLPK_integer(x.order.columns * x.order.columns) 217 | var work = [CDouble](count: Int(lwork), repeatedValue: 0.0) 218 | var error: __CLPK_integer = 0 219 | var nc = __CLPK_integer(x.order.columns) 220 | 221 | dgetrf_(&nc, &nc, &(results.grid), &nc, &ipiv, &error) 222 | dgetri_(&nc, &(results.grid), &nc, &ipiv, &work, &lwork, &error) 223 | 224 | assert(error == 0, "Matrix not invertible") 225 | 226 | return results 227 | } 228 | 229 | public func transpose(x: Matrix) -> Matrix { 230 | var results = Matrix(rows: x.order.columns, columns: x.order.rows, repeatedValue: 0.0) 231 | vDSP_mtrans(x.grid, 1, &(results.grid), 1, vDSP_Length(results.order.rows), vDSP_Length(results.order.columns)) 232 | 233 | return results 234 | } 235 | 236 | public func transpose(x: Matrix) -> Matrix { 237 | var results = Matrix(rows: x.order.columns, columns: x.order.rows, repeatedValue: 0.0) 238 | vDSP_mtransD(x.grid, 1, &(results.grid), 1, vDSP_Length(results.order.rows), vDSP_Length(results.order.columns)) 239 | 240 | return results 241 | } 242 | 243 | // MARK: - Operators 244 | 245 | public func + (lhs: Matrix, rhs: Matrix) -> Matrix { 246 | return add(lhs, y: rhs) 247 | } 248 | 249 | public func + (lhs: Matrix, rhs: Matrix) -> Matrix { 250 | return add(lhs, y: rhs) 251 | } 252 | 253 | public func * (lhs: Float, rhs: Matrix) -> Matrix { 254 | return mul(lhs, x: rhs) 255 | } 256 | 257 | public func * (lhs: Double, rhs: Matrix) -> Matrix { 258 | return mul(lhs, x: rhs) 259 | } 260 | 261 | public func * (lhs: Matrix, rhs: Matrix) -> Matrix { 262 | return mul(lhs, y: rhs) 263 | } 264 | 265 | public func * (lhs: Matrix, rhs: Matrix) -> Matrix { 266 | return mul(lhs, y: rhs) 267 | } 268 | 269 | postfix operator ′ {} 270 | public postfix func ′ (value: Matrix) -> Matrix { 271 | return transpose(value) 272 | } 273 | 274 | public postfix func ′ (value: Matrix) -> Matrix { 275 | return transpose(value) 276 | } 277 | -------------------------------------------------------------------------------- /SwiftMath/Surge/Power.swift: -------------------------------------------------------------------------------- 1 | // Power.swift 2 | // 3 | // Copyright (c) 2014–2015 Mattt Thompson (http://mattt.me) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | import Accelerate 24 | 25 | // MARK: Power 26 | 27 | public func power(x: [Real], y: [Real]) -> [Real] { 28 | return analysis(x, y, ifFloat: pow, ifDouble: pow) 29 | } 30 | 31 | func pow(x: [Float], y: [Float]) -> [Float] { 32 | var results = [Float](count: x.count, repeatedValue: 0.0) 33 | vvpowf(&results, x, y, [Int32(x.count)]) 34 | 35 | return results 36 | } 37 | 38 | func pow(x: [Double], y: [Double]) -> [Double] { 39 | var results = [Double](count: x.count, repeatedValue: 0.0) 40 | vvpow(&results, x, y, [Int32(x.count)]) 41 | 42 | return results 43 | } 44 | -------------------------------------------------------------------------------- /SwiftMath/Surge/RealTypeAnalysis.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RealTypeAnalysis.swift 3 | // SwiftMath 4 | // 5 | // Created by Matteo Battaglio on 23/08/15. 6 | // Copyright © 2015 Matteo Battaglio. All rights reserved. 7 | // 8 | 9 | func analysis(x: [Real], _ y: [Real], @noescape ifFloat: ([Float], [Float]) -> Float, @noescape ifDouble: ([Double], [Double]) -> Double) -> Real { 10 | if Real.self == Float.self { 11 | return Real(ifFloat(unsafeBitCast(x, [Float].self), unsafeBitCast(y, [Float].self))) 12 | } else if Real.self == Double.self { 13 | return Real(ifDouble(unsafeBitCast(x, [Double].self), unsafeBitCast(y, [Double].self))) 14 | } 15 | fatalError("Accelerate-backed array methods work only with Float or Double elements") 16 | } 17 | 18 | func analysis(x: [Real], _ y: [Real], @noescape ifFloat: ([Float], [Float]) -> [Float], @noescape ifDouble: ([Double], [Double]) -> [Double]) -> [Real] { 19 | if Real.self == Float.self { 20 | return unsafeBitCast(ifFloat(unsafeBitCast(x, [Float].self), unsafeBitCast(y, [Float].self)), [Real].self) 21 | } else if Real.self == Double.self { 22 | return unsafeBitCast(ifDouble(unsafeBitCast(x, [Double].self), unsafeBitCast(y, [Double].self)), [Real].self) 23 | } 24 | fatalError("Accelerate-backed array methods work only with Float or Double elements") 25 | } 26 | 27 | 28 | -------------------------------------------------------------------------------- /SwiftMath/Surge/RealTypeArrayExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RealTypeArrayExtension.swift 3 | // SwiftMath 4 | // 5 | // Created by Matteo Battaglio on 23/08/15. 6 | // Copyright © 2015 Matteo Battaglio. All rights reserved. 7 | // 8 | 9 | extension Array where Element: RealType { 10 | 11 | private func analysis(@noescape ifFloat ifFloat: ([Float]) -> Float, @noescape ifDouble: ([Double]) -> Double) -> Element { 12 | if Element.self == Float.self { 13 | return Element(ifFloat(unsafeBitCast(self, [Float].self))) 14 | } else if Element.self == Double.self { 15 | return Element(ifDouble(unsafeBitCast(self, [Double].self))) 16 | } 17 | fatalError("Accelerate-backed array methods work only with Float or Double elements") 18 | } 19 | 20 | private func analysis(@noescape ifFloat ifFloat: ([Float]) -> [Float], @noescape ifDouble: ([Double]) -> [Double]) -> [Element] { 21 | if Element.self == Float.self { 22 | return unsafeBitCast(ifFloat(unsafeBitCast(self, [Float].self)), [Element].self) 23 | } else if Element.self == Double.self { 24 | return unsafeBitCast(ifDouble(unsafeBitCast(self, [Double].self)), [Element].self) 25 | } 26 | fatalError("Accelerate-backed array methods work only with Float or Double elements") 27 | } 28 | 29 | private func analysis(@noescape ifFloat ifFloat: ([Float]) -> ([Float], [Float]), @noescape ifDouble: ([Double]) -> ([Double], [Double])) -> ([Element], [Element]) { 30 | if Element.self == Float.self { 31 | let result = ifFloat(unsafeBitCast(self, [Float].self)) 32 | return (unsafeBitCast(result.0, [Element].self), unsafeBitCast(result.1, [Element].self)) 33 | } else if Element.self == Double.self { 34 | let result = ifDouble(unsafeBitCast(self, [Double].self)) 35 | return (unsafeBitCast(result.0, [Element].self), unsafeBitCast(result.1, [Element].self)) 36 | } 37 | fatalError("Accelerate-backed array methods work only with Float or Double elements") 38 | } 39 | 40 | // MARK: Arithmetic 41 | 42 | public func sum() -> Element { 43 | return analysis(ifFloat: SwiftMath.sum, ifDouble: SwiftMath.sum) 44 | } 45 | 46 | public func absoluteSum() -> Element { 47 | return analysis(ifFloat: asum, ifDouble: asum) 48 | } 49 | 50 | public func maxElement() -> Element? { 51 | if self.isEmpty { return nil } 52 | return analysis(ifFloat: max, ifDouble: max) 53 | } 54 | 55 | public func minElement() -> Element? { 56 | if self.isEmpty { return nil } 57 | return analysis(ifFloat: min, ifDouble: min) 58 | } 59 | 60 | public func mean() -> Element { 61 | return analysis(ifFloat: SwiftMath.mean, ifDouble: SwiftMath.mean) 62 | } 63 | 64 | public func meanMagnitude() -> Element { 65 | return analysis(ifFloat: meamg, ifDouble: meamg) 66 | } 67 | 68 | public func meanSquareValue() -> Element { 69 | return analysis(ifFloat: measq, ifDouble: measq) 70 | } 71 | 72 | public func squareRoots() -> [Element] { 73 | return analysis(ifFloat: sqrt, ifDouble: sqrt) 74 | } 75 | 76 | // MARK: Auxiliary 77 | 78 | public func absolute() -> [Element] { 79 | return analysis(ifFloat: abs, ifDouble: abs) 80 | } 81 | 82 | public func ceiling() -> [Element] { 83 | return analysis(ifFloat: ceil, ifDouble: ceil) 84 | } 85 | 86 | public func floor() -> [Element] { 87 | return analysis(ifFloat: SwiftMath.floor, ifDouble: SwiftMath.floor) 88 | } 89 | 90 | public func negate() -> [Element] { 91 | return analysis(ifFloat: neg, ifDouble: neg) 92 | } 93 | 94 | public func reciprocal() -> [Element] { 95 | return analysis(ifFloat: rec, ifDouble: rec) 96 | } 97 | 98 | public func round() -> [Element] { 99 | return analysis(ifFloat: SwiftMath.round, ifDouble: SwiftMath.round) 100 | } 101 | 102 | public func truncate() -> [Element] { 103 | return analysis(ifFloat: trunc, ifDouble: trunc) 104 | } 105 | 106 | public func threshold(low: Element) -> [Element] { 107 | return analysis(ifFloat: { myself in 108 | SwiftMath.threshold(myself, low as! Float) 109 | }, ifDouble: { myself in 110 | SwiftMath.threshold(myself, low as! Double) 111 | }) 112 | } 113 | 114 | public func clip(interval: ClosedInterval) -> [Element] { 115 | return analysis(ifFloat: { myself in 116 | SwiftMath.clip(myself, interval.start as! Float, interval.end as! Float) 117 | }, ifDouble: { myself in 118 | SwiftMath.clip(myself, interval.start as! Double, interval.end as! Double) 119 | }) 120 | } 121 | 122 | // MARK: Exponential 123 | 124 | public func exponential() -> [Element] { 125 | return analysis(ifFloat: exp, ifDouble: exp) 126 | } 127 | 128 | public func squareExponential() -> [Element] { 129 | return analysis(ifFloat: exp2, ifDouble: exp2) 130 | } 131 | 132 | public func naturalLogarithm() -> [Element] { 133 | return analysis(ifFloat: log, ifDouble: log) 134 | } 135 | 136 | public func base2Logarithm() -> [Element] { 137 | return analysis(ifFloat: log2, ifDouble: log2) 138 | } 139 | 140 | public func base10Logarithm() -> [Element] { 141 | return analysis(ifFloat: log10, ifDouble: log10) 142 | } 143 | 144 | public func logarithmicExponential() -> [Element] { 145 | return analysis(ifFloat: logb, ifDouble: logb) 146 | } 147 | 148 | // MARK: Fast Fourier Transform 149 | 150 | public func fastFourierTransform() -> [Element] { 151 | return analysis(ifFloat: fft, ifDouble: fft) 152 | } 153 | 154 | // MARK: Trigonometric 155 | 156 | public func sine() -> [Element] { 157 | return analysis(ifFloat: sin, ifDouble: sin) 158 | } 159 | 160 | public func cosine() -> [Element] { 161 | return analysis(ifFloat: cos, ifDouble: cos) 162 | } 163 | 164 | public func sineCosine() -> (sin: [Element], cos: [Element]) { 165 | return analysis(ifFloat: sincos, ifDouble: sincos) 166 | } 167 | 168 | public func tangent() -> [Element] { 169 | return analysis(ifFloat: tan, ifDouble: tan) 170 | } 171 | 172 | public func ascsine() -> [Element] { 173 | return analysis(ifFloat: asin, ifDouble: asin) 174 | } 175 | 176 | public func arccosine() -> [Element] { 177 | return analysis(ifFloat: acos, ifDouble: acos) 178 | } 179 | 180 | public func arctangent() -> [Element] { 181 | return analysis(ifFloat: atan, ifDouble: atan) 182 | } 183 | 184 | public func radiansToDegrees() -> [Element] { 185 | return analysis(ifFloat: rad2deg, ifDouble: rad2deg) 186 | } 187 | 188 | public func degreesToRadians() -> [Element] { 189 | return analysis(ifFloat: deg2rad, ifDouble: deg2rad) 190 | } 191 | 192 | // MARK: Hyperbolic 193 | 194 | public func hyperbolicSine() -> [Element] { 195 | return analysis(ifFloat: sinh, ifDouble: sinh) 196 | } 197 | 198 | public func hyperbolicCosine() -> [Element] { 199 | return analysis(ifFloat: cosh, ifDouble: cosh) 200 | } 201 | 202 | public func hyperbolicTangent() -> [Element] { 203 | return analysis(ifFloat: tanh, ifDouble: tanh) 204 | } 205 | 206 | public func hyperbolicArcsine() -> [Element] { 207 | return analysis(ifFloat: asinh, ifDouble: asinh) 208 | } 209 | 210 | public func hyperbolicArccosine() -> [Element] { 211 | return analysis(ifFloat: acosh, ifDouble: acosh) 212 | } 213 | 214 | public func hyperbolicArctangent() -> [Element] { 215 | return analysis(ifFloat: atanh, ifDouble: atanh) 216 | } 217 | 218 | } 219 | -------------------------------------------------------------------------------- /SwiftMath/Surge/Trigonometric.swift: -------------------------------------------------------------------------------- 1 | // Trigonometric.swift 2 | // 3 | // Copyright (c) 2014–2015 Mattt Thompson (http://mattt.me) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | import Accelerate 24 | 25 | // MARK: Sine-Cosine 26 | 27 | public func sincos(x: [Float]) -> (sin: [Float], cos: [Float]) { 28 | var sin = [Float](count: x.count, repeatedValue: 0.0) 29 | var cos = [Float](count: x.count, repeatedValue: 0.0) 30 | vvsincosf(&sin, &cos, x, [Int32(x.count)]) 31 | 32 | return (sin, cos) 33 | } 34 | 35 | public func sincos(x: [Double]) -> (sin: [Double], cos: [Double]) { 36 | var sin = [Double](count: x.count, repeatedValue: 0.0) 37 | var cos = [Double](count: x.count, repeatedValue: 0.0) 38 | vvsincos(&sin, &cos, x, [Int32(x.count)]) 39 | 40 | return (sin, cos) 41 | } 42 | 43 | // MARK: Sine 44 | 45 | public func sin(x: [Float]) -> [Float] { 46 | var results = [Float](count: x.count, repeatedValue: 0.0) 47 | vvsinf(&results, x, [Int32(x.count)]) 48 | 49 | return results 50 | } 51 | 52 | public func sin(x: [Double]) -> [Double] { 53 | var results = [Double](count: x.count, repeatedValue: 0.0) 54 | vvsin(&results, x, [Int32(x.count)]) 55 | 56 | return results 57 | } 58 | 59 | // MARK: Cosine 60 | 61 | public func cos(x: [Float]) -> [Float] { 62 | var results = [Float](count: x.count, repeatedValue: 0.0) 63 | vvcosf(&results, x, [Int32(x.count)]) 64 | 65 | return results 66 | } 67 | 68 | public func cos(x: [Double]) -> [Double] { 69 | var results = [Double](count: x.count, repeatedValue: 0.0) 70 | vvcos(&results, x, [Int32(x.count)]) 71 | 72 | return results 73 | } 74 | 75 | // MARK: Tangent 76 | 77 | public func tan(x: [Float]) -> [Float] { 78 | var results = [Float](count: x.count, repeatedValue: 0.0) 79 | vvtanf(&results, x, [Int32(x.count)]) 80 | 81 | return results 82 | } 83 | 84 | public func tan(x: [Double]) -> [Double] { 85 | var results = [Double](count: x.count, repeatedValue: 0.0) 86 | vvtan(&results, x, [Int32(x.count)]) 87 | 88 | return results 89 | } 90 | 91 | // MARK: Arcsine 92 | 93 | public func asin(x: [Float]) -> [Float] { 94 | var results = [Float](count: x.count, repeatedValue: 0.0) 95 | vvasinf(&results, x, [Int32(x.count)]) 96 | 97 | return results 98 | } 99 | 100 | public func asin(x: [Double]) -> [Double] { 101 | var results = [Double](count: x.count, repeatedValue: 0.0) 102 | vvasin(&results, x, [Int32(x.count)]) 103 | 104 | return results 105 | } 106 | 107 | // MARK: Arccosine 108 | 109 | public func acos(x: [Float]) -> [Float] { 110 | var results = [Float](count: x.count, repeatedValue: 0.0) 111 | vvacosf(&results, x, [Int32(x.count)]) 112 | 113 | return results 114 | } 115 | 116 | public func acos(x: [Double]) -> [Double] { 117 | var results = [Double](count: x.count, repeatedValue: 0.0) 118 | vvacos(&results, x, [Int32(x.count)]) 119 | 120 | return results 121 | } 122 | 123 | // MARK: Arctangent 124 | 125 | public func atan(x: [Float]) -> [Float] { 126 | var results = [Float](count: x.count, repeatedValue: 0.0) 127 | vvatanf(&results, x, [Int32(x.count)]) 128 | 129 | return results 130 | } 131 | 132 | public func atan(x: [Double]) -> [Double] { 133 | var results = [Double](count: x.count, repeatedValue: 0.0) 134 | vvatan(&results, x, [Int32(x.count)]) 135 | 136 | return results 137 | } 138 | 139 | // MARK: - 140 | 141 | // MARK: Radians to Degrees 142 | 143 | func rad2deg(x: [Float]) -> [Float] { 144 | var results = [Float](count: x.count, repeatedValue: 0.0) 145 | let divisor = [Float](count: x.count, repeatedValue: Float(M_PI / 180.0)) 146 | vvdivf(&results, x, divisor, [Int32(x.count)]) 147 | 148 | return results 149 | } 150 | 151 | func rad2deg(x: [Double]) -> [Double] { 152 | var results = [Double](count: x.count, repeatedValue: 0.0) 153 | let divisor = [Double](count: x.count, repeatedValue: M_PI / 180.0) 154 | vvdiv(&results, x, divisor, [Int32(x.count)]) 155 | 156 | return results 157 | } 158 | 159 | // MARK: Degrees to Radians 160 | 161 | func deg2rad(x: [Float]) -> [Float] { 162 | var results = [Float](count: x.count, repeatedValue: 0.0) 163 | let divisor = [Float](count: x.count, repeatedValue: Float(180.0 / M_PI)) 164 | vvdivf(&results, x, divisor, [Int32(x.count)]) 165 | 166 | return results 167 | } 168 | 169 | func deg2rad(x: [Double]) -> [Double] { 170 | var results = [Double](count: x.count, repeatedValue: 0.0) 171 | let divisor = [Double](count: x.count, repeatedValue: 180.0 / M_PI) 172 | vvdiv(&results, x, divisor, [Int32(x.count)]) 173 | 174 | return results 175 | } 176 | -------------------------------------------------------------------------------- /SwiftMath/SwiftMath.h: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftMath.h 3 | // SwiftMath 4 | // 5 | // Created by Matteo Battaglio on 01/05/15. 6 | // Copyright (c) 2015 Matteo Battaglio. All rights reserved. 7 | // 8 | @import Foundation; 9 | 10 | //! Project version number for SwiftMath. 11 | FOUNDATION_EXPORT double SwiftMathVersionNumber; 12 | 13 | //! Project version string for SwiftMath. 14 | FOUNDATION_EXPORT const unsigned char SwiftMathVersionString[]; 15 | 16 | // In this header, you should import all the public headers of your framework using statements like #import 17 | 18 | 19 | -------------------------------------------------------------------------------- /SwiftMath/Vector.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Vector.swift 3 | // SwiftMath 4 | // 5 | // Created by Matteo Battaglio on 23/07/15. 6 | // Copyright © 2015 Matteo Battaglio. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct Vector: VectorType { 12 | 13 | public let coordinates: [Real] 14 | 15 | public init(_ coordinates: [Real]) { 16 | self.coordinates = coordinates 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /SwiftMath/Vector2.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Vector2.swift 3 | // SwiftMath 4 | // 5 | // Created by Matteo Battaglio on 16/07/15. 6 | // Copyright © 2015 Matteo Battaglio. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// Vector in the two-dimensional Euclidean space — R×R 12 | public struct Vector2: VectorType { 13 | 14 | public let x, y: Real 15 | 16 | public init(_ coordinates: [Real]) { 17 | guard coordinates.count == 2 else { 18 | fatalError("Vector2 must be initialized with an array of 2 values") 19 | } 20 | self.init(x: coordinates[0], y: coordinates[1]) 21 | } 22 | 23 | public init(x: Real, y: Real) { 24 | self.x = x 25 | self.y = y 26 | } 27 | 28 | public var coordinates: [Real] { 29 | return [x, y] 30 | } 31 | 32 | public var components: (x: Real, y: Real) { 33 | return (x, y) 34 | } 35 | 36 | public static func zero() -> Vector2 { 37 | return Vector2(x: 0, y: 0) 38 | } 39 | 40 | public func scale(value: Real) -> Vector2 { 41 | return Vector2(x: value * x, y: value * y) 42 | } 43 | 44 | public func dotProduct(vector: Vector2) -> Real { 45 | return (x * vector.x) + (y * vector.y) 46 | } 47 | 48 | } 49 | 50 | // MARK: Hashable 51 | 52 | extension Vector2 : Equatable, Hashable { 53 | 54 | public var hashValue: Int { 55 | if self.x is Double { 56 | return Int((x as! Double) + (y*10_000.0 as! Double)) 57 | } else { 58 | return Int((x as! Float) + (y*10_000.0 as! Float)) 59 | } 60 | } 61 | 62 | } 63 | 64 | public func == (lhs: Vector2, rhs: Vector2) -> Bool { 65 | return (lhs.x == rhs.x) && (lhs.y == rhs.y) 66 | } 67 | 68 | // MARK: Operators 69 | 70 | public func + (v1: Vector2, v2: Vector2) -> Vector2 { 71 | return Vector2(x: v1.x + v2.x, y: v1.y + v2.y) 72 | } 73 | 74 | public func - (v1: Vector2, v2: Vector2) -> Vector2 { 75 | return Vector2(x: v1.x - v2.x, y: v1.y - v2.y) 76 | } 77 | 78 | public prefix func - (vector: Vector2) -> Vector2 { 79 | return Vector2(x: -vector.x, y: -vector.y) 80 | } 81 | 82 | // MARK: CustomStringConvertible 83 | 84 | extension Vector2: CustomStringConvertible { 85 | 86 | public var description: String { 87 | return "(x: \(x), y: \(y))" 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /SwiftMath/Vector3.swift: -------------------------------------------------------------------------------- 1 | // 2 | // VectorMath.swift 3 | // SwiftMath 4 | // 5 | // Created by Matteo Battaglio on 24/12/14. 6 | // Copyright (c) 2014 Matteo Battaglio. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// Vector in the three-dimensional Euclidean space – R×R×R 12 | public struct Vector3: VectorType { 13 | 14 | public let x, y, z: Real 15 | 16 | public init(_ coordinates: [Real]) { 17 | guard coordinates.count == 3 else { 18 | fatalError("Vector3 must be initialized with an array of 3 values") 19 | } 20 | self.init(x: coordinates[0], y: coordinates[1], z: coordinates[2]) 21 | } 22 | 23 | public init(x: Real, y: Real, z: Real) { 24 | self.x = x 25 | self.y = y 26 | self.z = z 27 | } 28 | 29 | public var coordinates: [Real] { 30 | return [x, y, z] 31 | } 32 | 33 | public var components: (x: Real, y: Real, z: Real) { 34 | return (x, y, z) 35 | } 36 | 37 | public static func zero() -> Vector3 { 38 | return Vector3(x: 0, y: 0, z: 0) 39 | } 40 | 41 | public func scale(value: Real) -> Vector3 { 42 | return Vector3(x: value * x, y: value * y, z: value * z) 43 | } 44 | 45 | public func dotProduct(vector: Vector3) -> Real { 46 | return (x * vector.x) + (y * vector.y) + (z * vector.z) 47 | } 48 | 49 | public func crossProduct(vector: Vector3) -> Vector3 { 50 | let cx = y * vector.z - z * vector.y 51 | let cy = z * vector.x - x * vector.z 52 | let cz = x * vector.y - y * vector.x 53 | 54 | return Vector3(x: cx, y: cy, z: cz) 55 | } 56 | 57 | public func rotate(rotation: Quaternion) -> Vector3 { 58 | assert(rotation.length == 1.0, "rotation is not a unit-length quaternion") 59 | return self + (rotation.im + rotation.im) × (rotation.im × self + rotation.re * self) 60 | } 61 | 62 | } 63 | 64 | // MARK: Hashable 65 | 66 | extension Vector3 : Equatable, Hashable { 67 | 68 | public var hashValue: Int { 69 | if self.x is Double { 70 | return Int((x as! Double) + (y*10_000.0 as! Double) + (z*100_000_000.0 as! Double)) 71 | } else { 72 | return Int((x as! Float) + (y*10_000.0 as! Float) + (z*100_000_000.0 as! Float)) 73 | } 74 | } 75 | 76 | } 77 | 78 | public func == (lhs: Vector3, rhs: Vector3) -> Bool { 79 | return (lhs.x == rhs.x) && (lhs.y == rhs.y) && (lhs.z == rhs.z) 80 | } 81 | 82 | // MARK: Operators 83 | 84 | public func + (v1: Vector3, v2: Vector3) -> Vector3 { 85 | return Vector3(x: v1.x + v2.x, y: v1.y + v2.y, z: v1.z + v2.z) 86 | } 87 | 88 | public func - (v1: Vector3, v2: Vector3) -> Vector3 { 89 | return Vector3(x: v1.x - v2.x, y: v1.y - v2.y, z: v1.z - v2.z) 90 | } 91 | 92 | public prefix func - (vector: Vector3) -> Vector3 { 93 | return Vector3(x: -vector.x, y: -vector.y, z: -vector.z) 94 | } 95 | 96 | infix operator × { associativity left precedence 150 } 97 | /// Cross product 98 | public func × (v1: Vector3, v2: Vector3) -> Vector3 { 99 | return v1.crossProduct(v2) 100 | } 101 | 102 | extension Vector3: CustomStringConvertible { 103 | 104 | public var description: String { 105 | return "(x: \(x), y: \(y), z: \(z))" 106 | } 107 | 108 | } -------------------------------------------------------------------------------- /SwiftMath/VectorType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // VectorType.swift 3 | // SwiftMath 4 | // 5 | // Created by Matteo Battaglio on 16/07/15. 6 | // Copyright © 2015 Matteo Battaglio. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol VectorType: Equatable, ArrayLiteralConvertible, CustomStringConvertible { 12 | 13 | typealias Real: RealType 14 | 15 | init(_ coordinates: [Real]) 16 | 17 | init(_ coordinates: Real...) 18 | 19 | static func zero(dimension: Int) -> Self 20 | 21 | var coordinates: [Real] { get } 22 | 23 | var squareLength: Real { get } 24 | 25 | var length: Real { get } 26 | 27 | var norm: Real { get } 28 | 29 | func unit() -> Self 30 | 31 | // MARK: Operators 32 | 33 | func +(v1: Self, v2: Self) -> Self 34 | 35 | func -(v1: Self, v2: Self) -> Self 36 | 37 | func *(scalar: Real, vector: Self) -> Self 38 | 39 | func /(vector: Self, scalar: Real) -> Self 40 | 41 | prefix func -(vector: Self) -> Self 42 | 43 | func scale(value: Real) -> Self 44 | 45 | func dotProduct(vector: Self) -> Real 46 | 47 | func squareDistanceTo(vector: Self) -> Real 48 | 49 | } 50 | 51 | extension VectorType { 52 | 53 | public init(_ elements: Real...) { 54 | self.init(elements) 55 | } 56 | 57 | public init(arrayLiteral elements: Real...) { 58 | self.init(elements) 59 | } 60 | 61 | public static func zero(dimension: Int) -> Self { 62 | return Self(Array(count: dimension, repeatedValue: 0.0)) 63 | } 64 | 65 | public var squareLength: Real { 66 | return self.dotProduct(self) 67 | } 68 | 69 | public var length: Real { 70 | return norm 71 | } 72 | 73 | public var norm: Real { 74 | return squareLength.sqrt() 75 | } 76 | 77 | public func unit() -> Self { 78 | return self / length 79 | } 80 | 81 | public func scale(value: Real) -> Self { 82 | return Self(coordinates.map { $0 * value }) 83 | } 84 | 85 | public func dotProduct(vector: Self) -> Real { 86 | var i = 0 87 | return coordinates.reduce(Real(0)) { (sumOfProducts, coordinate) in 88 | sumOfProducts + coordinate*vector.coordinates[i++] 89 | } 90 | } 91 | 92 | public func distanceTo(vector: Self) -> Real { 93 | return (self - vector).length 94 | } 95 | 96 | public func squareDistanceTo(vector: Self) -> Real { 97 | return (self - vector).squareLength 98 | } 99 | 100 | } 101 | 102 | // MARK: Equatable 103 | 104 | public func == (lhs: Vector, rhs: Vector) -> Bool { 105 | return lhs.coordinates == rhs.coordinates 106 | } 107 | 108 | // MARK: Operators 109 | 110 | public func + (v1: Vector, v2: Vector) -> Vector { 111 | return zipAndCombine(v1, v2, +) 112 | } 113 | 114 | public prefix func - (vector: Vector) -> Vector { 115 | return Vector(vector.coordinates.map(-)) 116 | } 117 | 118 | public func - (v1: Vector, v2: Vector) -> Vector { 119 | return zipAndCombine(v1, v2, -) 120 | } 121 | 122 | public func * (scalar: Vector.Real, vector: Vector) -> Vector { 123 | return vector.scale(scalar) 124 | } 125 | 126 | public func * (vector: Vector, scalar: Vector.Real) -> Vector { 127 | return scalar * vector 128 | } 129 | 130 | public func / (vector: Vector, scalar: Vector.Real) -> Vector { 131 | return vector.scale(1.0/scalar) 132 | } 133 | 134 | /// Dot product 135 | public func * (v1: Vector, v2: Vector) -> Vector.Real { 136 | return v1.dotProduct(v2) 137 | } 138 | 139 | // MARK: CustomStringConvertible 140 | 141 | extension VectorType { 142 | 143 | public var description: String { 144 | return "(\(coordinates.map({ $0.description }).joinWithSeparator(", ")))" 145 | } 146 | 147 | } 148 | // MARK: Private functions 149 | 150 | private func zipAndCombine(v1: Vector, _ v2: Vector, _ op: (Vector.Real, Vector.Real) -> Vector.Real) -> Vector { 151 | return Vector(zip(v1.coordinates, v2.coordinates).map(op)) 152 | } 153 | -------------------------------------------------------------------------------- /SwiftMathTests/ComplexMultisetMatcher.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ComplexArrayMatcher.swift 3 | // SwiftMath 4 | // 5 | // Created by Matteo Battaglio on 10/05/15. 6 | // Copyright (c) 2015 Matteo Battaglio. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SwiftMath 11 | import Nimble 12 | import Set 13 | 14 | // Using the same value as Nimble's default delta constant 15 | let DefaultDelta = 0.0001 16 | 17 | public func isCloseTo(actual: Complex, _ expected: Complex) -> Bool { 18 | return abs(actual - expected) < T(DefaultDelta) 19 | } 20 | 21 | public func beCloseTo(var expectedValue: Multiset>) -> MatcherFunc>> { 22 | print("Expected value is: \(expectedValue)") 23 | return MatcherFunc { actualExpression, failureMessage in 24 | failureMessage.postfixMessage = "be close to <\(expectedValue)>" 25 | if let value = actualExpression.evaluate() { 26 | for element in value { 27 | var containedElement: Complex? = nil 28 | if expectedValue.contains(element) { 29 | containedElement = element 30 | } else { 31 | for expectedElement in expectedValue { 32 | if isCloseTo(element, expectedElement) { 33 | containedElement = expectedElement 34 | break 35 | } 36 | } 37 | } 38 | if containedElement != nil { 39 | expectedValue.remove(containedElement!) 40 | } else { 41 | return false 42 | } 43 | } 44 | print("Expected value NOW is: \(expectedValue)") 45 | return expectedValue.isEmpty 46 | } else { 47 | return false 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /SwiftMathTests/ComplexTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ComplexTests.swift 3 | // SwiftMath 4 | // 5 | // Created by Matteo Battaglio on 06/05/15. 6 | // Copyright (c) 2015 Matteo Battaglio. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SwiftMath 11 | import Quick 12 | import Nimble 13 | 14 | class ComplexSpec: QuickSpec { 15 | 16 | override func spec() { 17 | var c: Complex! 18 | var d: Complex! 19 | 20 | beforeEach { 21 | c = Complex(3.0, -5.0) 22 | d = Complex(-7.0, 120.0) 23 | } 24 | 25 | describe("complex number") { 26 | it("is real iff .im < epsilon") { 27 | let realComplex = Complex(42.0, 0.9*Double.epsilon) 28 | expect(realComplex.isReal).to(beTrue()) 29 | let nonRealComplex = Complex(42.0, 1.1*Double.epsilon) 30 | expect(nonRealComplex.isReal).to(beFalse()) 31 | } 32 | } 33 | 34 | describe("conjugation") { 35 | it("gives a complex number with the same real part and opposite imaginary part") { 36 | let expected = Complex(c.re, -c.im) 37 | expect(c.conj()).to(equal(expected)) 38 | } 39 | } 40 | 41 | describe("reciprocal") { 42 | it("is the division of itself by the sum of the squares of its real part and its imaginary part") { 43 | let expected = c.conj() / (c.re * c.re + c.im * c.im) 44 | expect(c.reciprocal()).to(equal(expected)) 45 | } 46 | } 47 | 48 | describe("addition") { 49 | it("consists of adding the real and imaginary parts of the summands") { 50 | let expected = Complex(c.re + d.re, c.im + d.im) 51 | expect(c + d).to(equal(expected)) 52 | } 53 | it("is commutative") { 54 | expect(c + d).to(equal(d + c)) 55 | } 56 | } 57 | 58 | describe("subtraction") { 59 | it("consists of subtracting the real and imaginary parts of the terms") { 60 | let expected = Complex(c.re - d.re, c.im - d.im) 61 | expect(c - d).to(equal(expected)) 62 | } 63 | } 64 | 65 | describe("multiplication") { 66 | it("implements the formula for complex number multiplication") { 67 | let expected = Complex(c.re * d.re - c.im * d.im, c.im * d.re + c.re * d.im) 68 | expect(c * d).to(equal(expected)) 69 | } 70 | it("is commutative") { 71 | expect(c * d).to(equal(d * c)) 72 | } 73 | } 74 | 75 | describe("division") { 76 | it("implements the formula for complex number division") { 77 | let denom = d.re * d.re + d.im * d.im 78 | let realPart = (c.re * d.re + c.im * d.im)/denom 79 | let imagPart = (c.im * d.re - c.re * d.im)/denom 80 | let expected = Complex(realPart, imagPart) 81 | expect(c / d).to(equal(expected)) 82 | } 83 | } 84 | 85 | describe("exponentiation") { 86 | it("correctly handles corner cases (i.e. x^0, 0^x)") { 87 | expect(Complex.zero() ** 0.0).to(equal(Complex(1.0, 0.0))) 88 | expect(Complex(9999.0, 0.0) ** 0.0).to(equal(Complex(1.0, 0.0))) 89 | expect(Complex.zero() ** 9999.0).to(equal(Complex.zero())) 90 | } 91 | } 92 | 93 | describe("principal square root") { 94 | it("equals itself exponentiated to the 0.5") { 95 | expect(sqrt(c)).to(equal(c ** 0.5)) 96 | } 97 | } 98 | } 99 | 100 | } -------------------------------------------------------------------------------- /SwiftMathTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /SwiftMathTests/PolynomialTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PolynomialTests.swift 3 | // SwiftMath 4 | // 5 | // Created by Matteo Battaglio on 07/05/15. 6 | // Copyright (c) 2015 Matteo Battaglio. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SwiftMath 11 | import Quick 12 | import Nimble 13 | import Set 14 | 15 | class PolynomialSpec: QuickSpec { 16 | 17 | override func spec() { 18 | let minus1 = -1 + 0.i 19 | let imaginary = 1.i 20 | 21 | describe("linear") { 22 | it("has 1 root [x = -b/a] iff a != 0") { 23 | expect(Polynomial(1, 1).roots()).to(equal(Multiset(minus1))) 24 | } 25 | it("has no solutions iff a == 0") { 26 | expect(Polynomial(0, 1).roots()).to(beEmpty()) 27 | } 28 | } 29 | 30 | describe("quadratic") { 31 | it("has 2 roots iff a != 0") { 32 | expect(Polynomial(1, 2, 1).roots()).to(equal(Multiset(minus1, minus1))) 33 | 34 | expect(Polynomial(1, 0, 1).roots()).to(equal(Multiset(-imaginary, imaginary))) 35 | } 36 | it("equals linear(b, c) iff a == 0") { 37 | expect(Polynomial(0, 1, 1).roots()).to(equal(Polynomial(1, 1).roots())) 38 | } 39 | } 40 | 41 | describe("cubic") { 42 | it("has 3 roots iff a != 0") { 43 | expect(Polynomial(1, 3, 3, 1).roots()).to(equal(Multiset(minus1, minus1, minus1))) 44 | 45 | expect(Polynomial(1, 1, 1, 1).roots()).to(beCloseTo(Multiset(minus1, -imaginary, imaginary))) 46 | } 47 | it("equals quadratic(b, c, d) iff a == 0") { 48 | expect(Polynomial(0, 1, 2, 1).roots()).to(equal(Polynomial(1, 2, 1).roots())) 49 | } 50 | } 51 | 52 | describe("quartic") { 53 | it("has 4 roots iff a != 0") { 54 | expect(Polynomial(5, 1, 3, -3, 10).roots().count).to(equal(4)) 55 | 56 | let x1 = -pow(-1+0.i, 0.2) 57 | let x2 = pow(-1+0.i, 0.4) 58 | let x3 = -pow(-1+0.i, 0.6) 59 | let x4 = pow(-1+0.i, 0.8) 60 | expect(Polynomial(1, 1, 1, 1, 1).roots()).to(beCloseTo(Multiset(x2, x3, x4, x1))) 61 | 62 | expect(Polynomial(1, 4, 6, 4, 1).roots()).to(equal(Multiset(minus1, minus1, minus1, minus1))) 63 | } 64 | it("equals cubic(b, c, d, e) iff a == 0") { 65 | expect(Polynomial(0, 1, 3, 3, 1).roots()).to(equal(Polynomial(1, 3, 3, 1).roots())) 66 | } 67 | it("has 0 as root, and the other three are cubic(a, b, c, d), if e == 0") { 68 | expect(Polynomial(1, 3, 3, 1, 0).roots()).to(equal([Complex.zero()] + Polynomial(1, 3, 3, 1).roots())) 69 | } 70 | } 71 | 72 | describe("Durand-Kerner-Weierstrass method") { 73 | it("is equivalent to the closed-form solution (where it exists)") { 74 | // Linear 75 | var coefficients: [Double] = [1, 1] 76 | var closedFormResult = Polynomial(coefficients).roots() 77 | var algorithmResult = Polynomial(coefficients).roots(preferClosedFormSolution: false) 78 | expect(algorithmResult).to(beCloseTo(closedFormResult)) 79 | 80 | coefficients = [-10, 50] 81 | closedFormResult = Polynomial(coefficients).roots() 82 | algorithmResult = Polynomial(coefficients).roots(preferClosedFormSolution: false) 83 | expect(algorithmResult).to(beCloseTo(closedFormResult)) 84 | 85 | // Quadratic 86 | coefficients = [1, 1, 1] 87 | closedFormResult = Polynomial(coefficients).roots() 88 | algorithmResult = Polynomial(coefficients).roots(preferClosedFormSolution: false) 89 | expect(algorithmResult).to(beCloseTo(closedFormResult)) 90 | 91 | coefficients = [-34, -5, 0.3] 92 | closedFormResult = Polynomial(coefficients).roots() 93 | algorithmResult = Polynomial(coefficients).roots(preferClosedFormSolution: false) 94 | expect(algorithmResult).to(beCloseTo(closedFormResult)) 95 | 96 | // Cubic 97 | coefficients = [1, 1, 1, 1] 98 | closedFormResult = Polynomial(coefficients).roots() 99 | algorithmResult = Polynomial(coefficients).roots(preferClosedFormSolution: false) 100 | expect(algorithmResult).to(beCloseTo(closedFormResult)) 101 | 102 | coefficients = [-34, -5, 0.3, 12345] 103 | closedFormResult = Polynomial(coefficients).roots() 104 | algorithmResult = Polynomial(coefficients).roots(preferClosedFormSolution: false) 105 | expect(algorithmResult).to(beCloseTo(closedFormResult)) 106 | 107 | // Quartic 108 | coefficients = [1, 1, 1, 1, 1] 109 | closedFormResult = Polynomial(coefficients).roots() 110 | algorithmResult = Polynomial(coefficients).roots(preferClosedFormSolution: false) 111 | expect(algorithmResult).to(beCloseTo(closedFormResult)) 112 | 113 | coefficients = [0.034, -540, 23, 12345, 0] 114 | closedFormResult = Polynomial(coefficients).roots() 115 | algorithmResult = Polynomial(coefficients).roots(preferClosedFormSolution: false) 116 | expect(algorithmResult).to(beCloseTo(closedFormResult)) 117 | } 118 | } 119 | } 120 | 121 | } -------------------------------------------------------------------------------- /SwiftMathTests/QuaternionTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // QuaternionTests.swift 3 | // SwiftMath 4 | // 5 | // Created by Matteo Battaglio on 31/05/15. 6 | // Copyright (c) 2015 GlidingSwift. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SwiftMath 11 | import Quick 12 | import Nimble 13 | 14 | class QuaternionSpec: QuickSpec { 15 | 16 | override func spec() { 17 | var c: Quaternion! 18 | var d: Quaternion! 19 | 20 | beforeEach { 21 | c = Quaternion(3, Vector3(x: 1, y: 2, z: 3)) 22 | d = Quaternion(7.0, Vector3(x: 5, y: 4, z: 3)) 23 | } 24 | 25 | describe("Quaternion") { 26 | it("is real iff .im == the zero vector") { 27 | let realQuaternion = Quaternion(42.0, .zero()) 28 | expect(realQuaternion.isReal).to(beTrue()) 29 | let nonRealQuaternion = Quaternion(42.0, Vector3(x: 1, y: 2, z: 3)) 30 | expect(nonRealQuaternion.isReal).to(beFalse()) 31 | } 32 | } 33 | 34 | describe("conjugation") { 35 | it("gives a quaternion with the same real part and opposite imaginary part") { 36 | let expected = Quaternion(c.re, -c.im) 37 | expect(c.conj()).to(equal(expected)) 38 | } 39 | } 40 | 41 | describe("reciprocal") { 42 | it("is the division of itself by the sum of the squares of its real part and its imaginary part") { 43 | let expected = c.conj() / (c.re * c.re + c.im * c.im) 44 | expect(c.reciprocal()).to(equal(expected)) 45 | } 46 | } 47 | 48 | describe("addition") { 49 | it("consists of adding the real and imaginary parts of the summands") { 50 | let expected = Quaternion(c.re + d.re, c.im + d.im) 51 | expect(c + d).to(equal(expected)) 52 | } 53 | it("is commutative") { 54 | expect(c + d).to(equal(d + c)) 55 | } 56 | } 57 | 58 | describe("subtraction") { 59 | it("consists of subtracting the real and imaginary parts of the terms") { 60 | let expected = Quaternion(c.re - d.re, c.im - d.im) 61 | expect(c - d).to(equal(expected)) 62 | } 63 | } 64 | 65 | describe("multiplication") { 66 | it("is commutative") { 67 | expect(c * d).to(equal(d * c)) 68 | } 69 | } 70 | 71 | } 72 | 73 | } -------------------------------------------------------------------------------- /SwiftMathTests/Surge/ArithmeticTests.swift: -------------------------------------------------------------------------------- 1 | // ArithmeticTests.swift 2 | // 3 | // Copyright (c) 2014–2015 Mattt Thompson (http://mattt.me) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | import Foundation 24 | import Surge 25 | import XCTest 26 | 27 | class ArithmeticTests: XCTestCase { 28 | let n = 100000 29 | 30 | func test_sqrt() { 31 | let values = (0...n).map{_ in Double(arc4random())} 32 | measureAndValidateMappedFunctionWithAccuracy(values, member: sqrt, mapped: sqrt, accuracy: 0.0001) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /SwiftMathTests/Surge/AuxiliaryTests.swift: -------------------------------------------------------------------------------- 1 | // AuxiliaryTests.swift 2 | // 3 | // Copyright (c) 2014–2015 Mattt Thompson (http://mattt.me) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | import Foundation 24 | import Surge 25 | import XCTest 26 | 27 | class AuxiliaryTests: XCTestCase { 28 | let n = 10000 29 | 30 | func test_copysign() { 31 | let signs = [Double]((0..>(source: C, member: (C.Generator.Element) -> (C.Generator.Element), mapped: (C) -> ([C.Generator.Element]), accuracy: C.Generator.Element) { 28 | var expected = source.map(member) 29 | 30 | var actual: [C.Generator.Element] = [] 31 | self.measureBlock { 32 | actual = mapped(source) 33 | } 34 | 35 | for (i, _) in source.enumerate() { 36 | XCTAssertEqualWithAccuracy(actual[i], expected[i], accuracy: accuracy) 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /SwiftMathTests/Vector3Matcher.swift: -------------------------------------------------------------------------------- 1 | // 2 | // VectorR3Matcher.swift 3 | // SwiftMath 4 | // 5 | // Created by Matteo Battaglio on 01/06/15. 6 | // Copyright (c) 2015 GlidingSwift. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SwiftMath 11 | import Nimble 12 | 13 | public func isCloseTo(actual: Vector3, _ expected: Vector3) -> Bool { 14 | let diff = actual - expected 15 | return diff.x.abs < T(DefaultDelta) && 16 | diff.y.abs < T(DefaultDelta) && 17 | diff.z.abs < T(DefaultDelta) 18 | } 19 | 20 | public func beCloseTo(expectedValue: Vector3) -> MatcherFunc> { 21 | return MatcherFunc { actualExpression, failureMessage in 22 | failureMessage.postfixMessage = "be close to <\(expectedValue)>" 23 | if let value = actualExpression.evaluate() { 24 | return isCloseTo(value, expectedValue) 25 | } else { 26 | return false 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /SwiftMathTests/Vector3Tests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // VectorR3Tests.swift 3 | // SwiftMath 4 | // 5 | // Created by Matteo Battaglio on 31/05/15. 6 | // Copyright (c) 2015 GlidingSwift. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SwiftMath 11 | import Quick 12 | import Nimble 13 | 14 | class Vector3Spec: QuickSpec { 15 | 16 | override func spec() { 17 | let v1 = Vector3(x: 1, y: 2, z: 3) 18 | let v2 = Vector3(x: 5, y: 6, z: 7) 19 | let v3 = Vector3(x: -20, y: 0, z: -5) 20 | 21 | describe("addition") { 22 | it("sums each component of one vector to the corresponding component of the other vector") { 23 | expect(v1 + v2).to(equal(Vector3(x: v1.x + v2.x, y: v1.y + v2.y, z: v1.z + v2.z))) 24 | } 25 | it("is commutative") { 26 | expect(v1 + v2).to(equal(v2 + v1)) 27 | } 28 | it("is associative") { 29 | expect(v1 + (v2 + v3)).to(equal((v1 + v2) + v3)) 30 | } 31 | it("has an identity element: the zero vector") { 32 | expect(v1 + .zero()).to(equal(v1)) 33 | } 34 | } 35 | 36 | describe("subtraction") { 37 | it("subtracts each component of one vector from the corresponding component of the other vector") { 38 | expect(v1 - v2).to(equal(Vector3(x: v1.x - v2.x, y: v1.y - v2.y, z: v1.z - v2.z))) 39 | } 40 | } 41 | 42 | describe("multiplication") { 43 | it("is associative") { 44 | expect(3 * (2 * v1)).to(equal((3 * 2) * v1)) 45 | } 46 | it("is distributive") { 47 | var expected = (5 * v1) + (5 * v2) 48 | expect(5 * (v1 + v2)).to(equal(expected)) 49 | 50 | expected = (5 * v1) + (6 * v1) 51 | expect((5 + 6) * v1).to(equal(expected)) 52 | } 53 | } 54 | 55 | describe("rotation") { 56 | it("rotates a vector as expected") { 57 | let original = Vector3(x: 3, y: 4, z: 0) 58 | let rotation = Quaternion(axis: Vector3(x: 1, y: 0, z: 0), angle: Double.PI/2.0) 59 | let result = original.rotate(rotation) 60 | let expected = Vector3(x: 3, y: 0, z: 4.0) 61 | expect(result).to(beCloseTo(expected)) 62 | 63 | expect(result.length).to(equal(original.length)) 64 | } 65 | } 66 | 67 | } 68 | 69 | } --------------------------------------------------------------------------------