Added functions for generating uniform/normal distributed randomness (#154)

Added functions for generating uniform/normal distributed randomness
This commit is contained in:
Vincent Esche 2019-10-29 18:10:20 +01:00 committed by GitHub
parent 4c3a462741
commit d2318c4c34
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 604 additions and 4 deletions

View File

@ -16,7 +16,6 @@ opt_in_rules:
- empty_count
- explicit_enum_raw_value
- explicit_init
- extension_access_modifier
- fatal_error_message
- file_header
- first_where

View File

@ -649,7 +649,7 @@ func powInPlace<L>(_ lhs: inout L, _ rhs: Double) where L: UnsafeMutableMemoryAc
return powInPlace(&lhs, rhs)
}
//// MARK: - Square
// MARK: - Square
public func sq<L>(_ lhs: L) -> [Float] where L: UnsafeMemoryAccessible, L.Element == Float {
return withArray(from: lhs) { sqInPlace(&$0) }

View File

@ -124,7 +124,149 @@ public struct Matrix<Scalar> where Scalar: FloatingPoint, Scalar: ExpressibleByF
return matrix
}
}
// MARK: - Initialization: Randomized
extension Matrix where Scalar == Float {
/// Generates a matrix of uniform-distributed random values within a (closed) `range`.
public static func random(
rows: Int,
columns: Int,
in range: ClosedRange<Float> = 0.0...1.0
) -> Matrix {
var generator = SystemRandomNumberGenerator()
return self.random(
rows: rows,
columns: columns,
in: range,
using: &generator
)
}
/// Generates a matrix of uniform-distributed random values within
/// a (closed) `range`, based on the provided random-number `generator`.
public static func random<T>(
rows: Int,
columns: Int,
in range: ClosedRange<Float> = 0.0...1.0,
using generator: inout T
) -> Matrix where T: RandomNumberGenerator {
let grid = Surge.random(
count: rows * columns,
in: range,
using: &generator
)
return Matrix(rows: rows, columns: columns, grid: grid)
}
/// Generates a matrix of normal-distributed random values with given
/// `mu` (mean) and `sigma` (std deviation).
public static func randomNormal(
rows: Int,
columns: Int,
mu: Float = 0.0,
sigma: Float = 1.0
) -> Matrix {
var generator = SystemRandomNumberGenerator()
return self.randomNormal(
rows: rows,
columns: columns,
mu: mu,
sigma: sigma,
using: &generator
)
}
/// Generates a matrix of normal-distributed random values with given
/// `mu` (mean) and `sigma` (std deviation) based on the provided random-number `generator`.
public static func randomNormal<T>(
rows: Int,
columns: Int,
mu: Float = 0.0,
sigma: Float = 1.0,
using generator: inout T
) -> Matrix where T: RandomNumberGenerator {
let grid = Surge.randomNormal(
count: rows * columns,
mu: mu,
sigma: sigma,
using: &generator
)
return Matrix(rows: rows, columns: columns, grid: grid)
}
}
extension Matrix where Scalar == Double {
/// Generates a matrix of uniform-distributed random values within a (closed) `range`.
public static func random(
rows: Int,
columns: Int,
in range: ClosedRange<Double> = 0.0...1.0
) -> Matrix {
var generator = SystemRandomNumberGenerator()
return self.random(
rows: rows,
columns: columns,
in: range,
using: &generator
)
}
/// Generates a matrix of uniform-distributed random values within
/// a (closed) `range`, based on the provided random-number `generator`.
public static func random<T>(
rows: Int,
columns: Int,
in range: ClosedRange<Double> = 0.0...1.0,
using generator: inout T
) -> Matrix where T: RandomNumberGenerator {
let grid = Surge.random(
count: rows * columns,
in: range,
using: &generator
)
return Matrix(rows: rows, columns: columns, grid: grid)
}
/// Generates a matrix of normal-distributed random values with given
/// `mu` (mean) and `sigma` (std deviation).
public static func randomNormal(
rows: Int,
columns: Int,
mu: Double = 0.0,
sigma: Double = 1.0
) -> Matrix {
var generator = SystemRandomNumberGenerator()
return self.randomNormal(
rows: rows,
columns: columns,
mu: mu,
sigma: sigma,
using: &generator
)
}
/// Generates a matrix of normal-distributed random values with given
/// `mu` (mean) and `sigma` (std deviation) based on the provided random-number `generator`.
public static func randomNormal<T>(
rows: Int,
columns: Int,
mu: Double = 0.0,
sigma: Double = 1.0,
using generator: inout T
) -> Matrix where T: RandomNumberGenerator {
let grid = Surge.randomNormal(
count: rows * columns,
mu: mu,
sigma: sigma,
using: &generator
)
return Matrix(rows: rows, columns: columns, grid: grid)
}
}
extension Matrix {
// MARK: - Subscript
public subscript(row: Int, column: Int) -> Scalar {

View File

@ -83,3 +83,61 @@ public func * (lhs: Float, rhs: Matrix<Float>) -> Matrix<Float> {
public func * (lhs: Double, rhs: Matrix<Double>) -> Matrix<Double> {
return mul(lhs, rhs)
}
extension Float {
/// Generates a normal-distributed random value with given
/// `mu` (mean) and `sigma` (std deviation).
public static func randomNormal(
mu: Float = 0.0,
sigma: Float = 1.0
) -> Float {
var generator = SystemRandomNumberGenerator()
return randomNormal(mu: mu, sigma: sigma, using: &generator)
}
/// Generates a normal-distributed random value with given
/// `mu` (mean) and `sigma` (std deviation) based on the provided random-number `generator`.
public static func randomNormal<T>(
mu: Float = 0.0,
sigma: Float = 1.0,
using generator: inout T
) -> Float where T: RandomNumberGenerator {
let lhs = Float.random(in: 0.0...1.0, using: &generator)
let rhs = Float.random(in: 0.0...1.0, using: &generator)
let z = sqrt(-2.0 * log(lhs)) * cos(2.0 * .pi * rhs)
// After applying the transform `z` holds values with a sigma of `1.0` and a mu of `0.0`.
return z * sigma + mu
}
}
extension Double {
/// Generates a normal-distributed random value with given
/// `mu` (mean) and `sigma` (std deviation).
public static func randomNormal(
mu: Double = 0.0,
sigma: Double = 1.0
) -> Double {
var generator = SystemRandomNumberGenerator()
return randomNormal(mu: mu, sigma: sigma, using: &generator)
}
/// Generates a normal-distributed random value with given
/// `mu` (mean) and `sigma` (std deviation) based on the provided random-number `generator`.
public static func randomNormal<T>(
mu: Double = 0.0,
sigma: Double = 1.0,
using generator: inout T
) -> Double where T: RandomNumberGenerator {
let lhs = Double.random(in: 0.0...1.0, using: &generator)
let rhs = Double.random(in: 0.0...1.0, using: &generator)
let z = sqrt(-2.0 * log(lhs)) * cos(2.0 * .pi * rhs)
// After applying the transform `z` holds values with a sigma of `1.0` and a mu of `0.0`.
return z * sigma + mu
}
}

View File

@ -43,6 +43,10 @@ public struct Vector<Scalar> where Scalar: FloatingPoint, Scalar: ExpressibleByF
} else {
scalars = Array(contents)
}
self.init(scalars: scalars)
}
public init(scalars: [Scalar]) {
self.dimensions = scalars.count
self.scalars = scalars
}
@ -59,6 +63,98 @@ public struct Vector<Scalar> where Scalar: FloatingPoint, Scalar: ExpressibleByF
}
}
// MARK: - Initialization: Randomized
extension Vector where Scalar == Float {
/// Generates a vector of uniform-distributed random values within a (closed) `range`.
public static func random(
count: Int,
in range: ClosedRange<Float> = 0.0...1.0
) -> Vector {
var generator = SystemRandomNumberGenerator()
return self.random(count: count, in: range, using: &generator)
}
/// Generates a vector of uniform-distributed random values within
/// a (closed) `range`, based on the provided random-number `generator`.
public static func random<T>(
count: Int,
in range: ClosedRange<Float> = 0.0...1.0,
using generator: inout T
) -> Vector where T: RandomNumberGenerator {
let scalars = Surge.random(count: count, in: range, using: &generator)
return Vector(scalars: scalars)
}
/// Generates a vector of normal-distributed random values with given
/// `mu` (mean) and `sigma` (std deviation).
public static func randomNormal(
count: Int,
mu: Float = 0.0,
sigma: Float = 1.0
) -> Vector {
var generator = SystemRandomNumberGenerator()
return self.randomNormal(count: count, mu: mu, sigma: sigma, using: &generator)
}
/// Generates a vector of normal-distributed random values with given
/// `mu` (mean) and `sigma` (std deviation) based on the provided random-number `generator`.
public static func randomNormal<T>(
count: Int,
mu: Float = 0.0,
sigma: Float = 1.0,
using generator: inout T
) -> Vector where T: RandomNumberGenerator {
let scalars = Surge.randomNormal(count: count, mu: mu, sigma: sigma, using: &generator)
return Vector(scalars: scalars)
}
}
extension Vector where Scalar == Double {
/// Generates a vector of uniform-distributed random values within a (closed) `range`.
public static func random(
count: Int,
in range: ClosedRange<Double> = 0.0...1.0
) -> Vector {
var generator = SystemRandomNumberGenerator()
return self.random(count: count, in: range, using: &generator)
}
/// Generates a vector of uniform-distributed random values within
/// a (closed) `range`, based on the provided random-number `generator`.
public static func random<T>(
count: Int,
in range: ClosedRange<Double> = 0.0...1.0,
using generator: inout T
) -> Vector where T: RandomNumberGenerator {
let scalars = Surge.random(count: count, in: range, using: &generator)
return Vector(scalars: scalars)
}
/// Generates a vector of normal-distributed random values with given
/// `mu` (mean) and `sigma` (std deviation).
public static func randomNormal(
count: Int,
mu: Double = 0.0,
sigma: Double = 1.0
) -> Vector {
var generator = SystemRandomNumberGenerator()
return self.randomNormal(count: count, mu: mu, sigma: sigma, using: &generator)
}
/// Generates a vector of normal-distributed random values with given
/// `mu` (mean) and `sigma` (std deviation) based on the provided random-number `generator`.
public static func randomNormal<T>(
count: Int,
mu: Double = 0.0,
sigma: Double = 1.0,
using generator: inout T
) -> Vector where T: RandomNumberGenerator {
let scalars = Surge.randomNormal(count: count, mu: mu, sigma: sigma, using: &generator)
return Vector(scalars: scalars)
}
}
// MARK: - ExpressibleByArrayLiteral
extension Vector: ExpressibleByArrayLiteral {

View File

@ -0,0 +1,209 @@
// Copyright © 2014-2019 the Surge contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
// MARK: - Random: Uniform Distribution
/// Generates an array of uniform-distributed random values within a (closed) `range`.
public func random(
count: Int,
in range: ClosedRange<Float> = 0.0...1.0
) -> [Float] {
var generator = SystemRandomNumberGenerator()
return random(count: count, in: range, using: &generator)
}
/// Generates an array of uniform-distributed random values within a (closed) `range`.
public func random(
count: Int,
in range: ClosedRange<Double> = 0.0...1.0
) -> [Double] {
var generator = SystemRandomNumberGenerator()
return random(count: count, in: range, using: &generator)
}
/// Generates an array of uniform-distributed random values within a
/// (closed) `range` based on the provided random-number `generator`.
public func random<T>(
count: Int,
in range: ClosedRange<Float>,
using generator: inout T
) -> [Float] where T: RandomNumberGenerator {
return (0..<count).map { _ in Float.random(in: range, using: &generator) }
}
/// Generates an array of uniform-distributed random values within a
/// (closed) `range` based on the provided random-number `generator`.
public func random<T>(
count: Int,
in range: ClosedRange<Double>,
using generator: inout T
) -> [Double] where T: RandomNumberGenerator {
return (0..<count).map { _ in Double.random(in: range, using: &generator) }
}
/// Generates an array of normal-distributed random values with given
/// `mu` (mean) and `sigma` (std deviation).
public func randomNormal(
count: Int,
mu: Float = 0.0,
sigma: Float = 1.0
) -> [Float] {
var generator = SystemRandomNumberGenerator()
return randomNormal(count: count, mu: mu, sigma: sigma, using: &generator)
}
/// Generates an array of normal-distributed random values with given
/// `mu` (mean) and `sigma` (std deviation).
public func randomNormal(
count: Int,
mu: Double = 0.0,
sigma: Double = 1.0
) -> [Double] {
var generator = SystemRandomNumberGenerator()
return randomNormal(count: count, mu: mu, sigma: sigma, using: &generator)
}
/// Generates an array of normal-distributed random values with given
/// `mu` (mean) and `sigma` (std deviation) based on the provided random-number `generator`.
public func randomNormal<T>(
count: Int,
mu: Float = 0.0,
sigma: Float = 1.0,
using generator: inout T
) -> [Float] where T: RandomNumberGenerator {
var lhs: [Float] = random(count: count, in: 0.0...1.0, using: &generator)
var rhs: [Float] = random(count: count, in: 0.0...1.0, using: &generator)
boxMullerTransformInPlace(&lhs, &rhs)
// After applying the transform `lhs` holds values with a sigma of `1.0` and a mu of `0.0`.
// stdNormal * sigma + mu
mulInPlace(&lhs, sigma)
addInPlace(&lhs, mu)
return lhs
}
/// Generates an array of normal-distributed random values with given
/// `mu` (mean) and `sigma` (std deviation) based on the provided random-number `generator`.
public func randomNormal<T>(
count: Int,
mu: Double = 0.0,
sigma: Double = 1.0,
using generator: inout T
) -> [Double] where T: RandomNumberGenerator {
// Box-Muller transform
var lhs: [Double] = random(count: count, in: 0.0...1.0, using: &generator)
var rhs: [Double] = random(count: count, in: 0.0...1.0, using: &generator)
boxMullerTransformInPlace(&lhs, &rhs)
// After applying the transform `lhs` holds values with a sigma of `1.0` and a mu of `0.0`.
// stdNormal * sigma + mu
mulInPlace(&lhs, sigma)
addInPlace(&lhs, mu)
return lhs
}
/// Performs the Box-Muller transform in-place.
///
/// - Note:
/// Upon return `lhs` will contain the result of the transform,
/// while `rhs` will will contain discardable, undefined content.
internal func boxMullerTransformInPlace<L, R>(
_ lhs: inout L,
_ rhs: inout R
) where L: UnsafeMutableMemoryAccessible, R: UnsafeMutableMemoryAccessible, L.Element == Float, R.Element == Float {
// Semantically this function calculates the following formula,
// implementing to the Box-Muller transform:
//
// ```
// return sqrt(-2.0 * log(lhs)) .* cos(2.0 * .pi * rhs)
// ```
//
// But instead of creating (and shortly later disposing) a temporary array
// on every partial expression we perform them efficiently in-place,
// allocating and re-using nothing but the initial buffers `u1` and `u2`:
//
// The in-place operations correspond to above formula like this:
//
// 2
// 1
// 0
// sqrt(-2.0 * log(lhs)) .* cos(2.0 * .pi * rhs)
// 3
// 4
// 5
logInPlace(&lhs) // 0
mulInPlace(&lhs, -2.0) // 1
sqrtInPlace(&lhs) // 2
mulInPlace(&rhs, 2.0 * .pi) // 3
cosInPlace(&rhs) // 4
elmulInPlace(&lhs, rhs) // 5
}
/// Performs the Box-Muller transform in-place.
///
/// - Note:
/// Upon return `lhs` will contain the result of the transform,
/// while `rhs` will will contain discardable, undefined content.
internal func boxMullerTransformInPlace<L, R>(
_ lhs: inout L,
_ rhs: inout R
) where L: UnsafeMutableMemoryAccessible, R: UnsafeMutableMemoryAccessible, L.Element == Double, R.Element == Double {
// Semantically this function calculates the following formula,
// implementing to the Box-Muller transform:
//
// ```
// return sqrt(-2.0 * log(lhs)) .* cos(2.0 * .pi * rhs)
// ```
//
// But instead of creating (and shortly later disposing) a temporary array
// on every partial expression we perform them efficiently in-place,
// allocating and re-using nothing but the initial buffers `u1` and `u2`:
//
// The in-place operations correspond to above formula like this:
//
// 2
// 1
// 0
// sqrt(-2.0 * log(lhs)) .* cos(2.0 * .pi * rhs)
// 3
// 4
// 5
logInPlace(&lhs) // 0
mulInPlace(&lhs, -2.0) // 1
sqrtInPlace(&lhs) // 2
mulInPlace(&rhs, 2.0 * .pi) // 3
cosInPlace(&rhs) // 4
elmulInPlace(&lhs, rhs) // 5
}

View File

@ -91,9 +91,16 @@
CAAF500C233A7B6700CC0AA7 /* Surge.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 614AD31F1FC0AD99002BFE1C /* Surge.framework */; };
CAAF5015233A7D4100CC0AA7 /* ArithmeticTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAF5014233A7C7900CC0AA7 /* ArithmeticTests.swift */; };
CAAF501A233A9E6300CC0AA7 /* SurgeBenchmarkTests+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAAF5019233A9E6300CC0AA7 /* SurgeBenchmarkTests+Extensions.swift */; };
CAD8E5BE2343D796001B172A /* Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAD8E5BD2343D796001B172A /* Random.swift */; };
CAD8E5BF2343D884001B172A /* Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAD8E5BD2343D796001B172A /* Random.swift */; };
CAD8E5C02343D885001B172A /* Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAD8E5BD2343D796001B172A /* Random.swift */; };
CAD8E5C12343D885001B172A /* Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAD8E5BD2343D796001B172A /* Random.swift */; };
CAD8E5CB2343FD38001B172A /* StatisticsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAD8E5CA2343FD38001B172A /* StatisticsTests.swift */; };
CAD8E5CC2343FD38001B172A /* StatisticsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAD8E5CA2343FD38001B172A /* StatisticsTests.swift */; };
CAD8E5CD2343FD38001B172A /* StatisticsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAD8E5CA2343FD38001B172A /* StatisticsTests.swift */; };
CAD8E5CF23441B33001B172A /* RandomTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAD8E5CE23441B33001B172A /* RandomTests.swift */; };
CAD8E5D023441B33001B172A /* RandomTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAD8E5CE23441B33001B172A /* RandomTests.swift */; };
CAD8E5D123441B33001B172A /* RandomTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAD8E5CE23441B33001B172A /* RandomTests.swift */; };
CAEC79BF2319274F00516E10 /* OperatorPrecedences.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAEC79B72319244D00516E10 /* OperatorPrecedences.swift */; };
CAEC79C02319275000516E10 /* OperatorPrecedences.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAEC79B72319244D00516E10 /* OperatorPrecedences.swift */; };
CAEC79C12319275000516E10 /* OperatorPrecedences.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAEC79B72319244D00516E10 /* OperatorPrecedences.swift */; };
@ -191,7 +198,9 @@
CAAF500B233A7B6700CC0AA7 /* Info-BenchmarkTests.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-BenchmarkTests.plist"; sourceTree = "<group>"; };
CAAF5014233A7C7900CC0AA7 /* ArithmeticTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArithmeticTests.swift; sourceTree = "<group>"; };
CAAF5019233A9E6300CC0AA7 /* SurgeBenchmarkTests+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SurgeBenchmarkTests+Extensions.swift"; sourceTree = "<group>"; };
CAD8E5BD2343D796001B172A /* Random.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Random.swift; sourceTree = "<group>"; };
CAD8E5CA2343FD38001B172A /* StatisticsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatisticsTests.swift; sourceTree = "<group>"; };
CAD8E5CE23441B33001B172A /* RandomTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RandomTests.swift; sourceTree = "<group>"; };
CAEC79B72319244D00516E10 /* OperatorPrecedences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OperatorPrecedences.swift; sourceTree = "<group>"; };
CAEC79C323192FE300516E10 /* Scalar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Scalar.swift; sourceTree = "<group>"; };
CAEC79D12319343100516E10 /* Logarithm.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Logarithm.swift; sourceTree = "<group>"; };
@ -287,6 +296,7 @@
CAEC79CD2319338F00516E10 /* Linear Algebra */,
CAEC79D02319343100516E10 /* Logarithm */,
CAEC79CC2319337700516E10 /* Statistics */,
CA874E39236894C900C485CB /* Random */,
CAEC79CE231933D700516E10 /* Trigonometry */,
CAEC79C8231932E900516E10 /* Utilities */,
);
@ -305,12 +315,21 @@
CAFE5DAD22F9ED4900A34887 /* VectorTests.swift */,
CAAF4FCF2338F09700CC0AA7 /* ScalarTests.swift */,
CAD8E5CA2343FD38001B172A /* StatisticsTests.swift */,
CAD8E5CE23441B33001B172A /* RandomTests.swift */,
CAFE5DA422F9EC1D00A34887 /* XCTAssert+Surge.swift */,
CA945C2C233ABC0D00D95127 /* SurgeTests+Extensions.swift */,
);
path = SurgeTests;
sourceTree = "<group>";
};
CA874E39236894C900C485CB /* Random */ = {
isa = PBXGroup;
children = (
CAD8E5BD2343D796001B172A /* Random.swift */,
);
path = Random;
sourceTree = "<group>";
};
CAAF5008233A7B6700CC0AA7 /* SurgeBenchmarkTests */ = {
isa = PBXGroup;
children = (
@ -840,6 +859,7 @@
614AD33E1FC0AF72002BFE1C /* Matrix.swift in Sources */,
61E930C32070B69300694FCB /* UnsafeMutableMemory.swift in Sources */,
61E930C92070BCCD00694FCB /* ArraySlice+Extensions.swift in Sources */,
CAD8E5BF2343D884001B172A /* Random.swift in Sources */,
CAEC79D32319343100516E10 /* Logarithm.swift in Sources */,
614AD3391FC0AF72002BFE1C /* Auxiliary.swift in Sources */,
614AD3411FC0AF72002BFE1C /* Trigonometric.swift in Sources */,
@ -860,6 +880,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
CAD8E5D023441B33001B172A /* RandomTests.swift in Sources */,
CAAF5001233A701A00CC0AA7 /* LogarithmTests.swift in Sources */,
614AD3481FC0AF77002BFE1C /* MatrixTests.swift in Sources */,
CAAF4FFD2339651700CC0AA7 /* ScalarTests.swift in Sources */,
@ -881,6 +902,7 @@
614AD36F1FC0B0CC002BFE1C /* Matrix.swift in Sources */,
61E930C42070B69300694FCB /* UnsafeMutableMemory.swift in Sources */,
61E930CA2070BCCD00694FCB /* ArraySlice+Extensions.swift in Sources */,
CAD8E5C02343D885001B172A /* Random.swift in Sources */,
CAEC79D42319343100516E10 /* Logarithm.swift in Sources */,
614AD36A1FC0B0CC002BFE1C /* Auxiliary.swift in Sources */,
614AD3721FC0B0CC002BFE1C /* Trigonometric.swift in Sources */,
@ -901,6 +923,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
CAD8E5D123441B33001B172A /* RandomTests.swift in Sources */,
CAAF5002233A701A00CC0AA7 /* LogarithmTests.swift in Sources */,
614AD3791FC0B0D2002BFE1C /* MatrixTests.swift in Sources */,
CAAF4FFE2339651800CC0AA7 /* ScalarTests.swift in Sources */,
@ -922,6 +945,7 @@
614AD3911FC0B134002BFE1C /* Matrix.swift in Sources */,
61E930C52070B69300694FCB /* UnsafeMutableMemory.swift in Sources */,
61E930CB2070BCCD00694FCB /* ArraySlice+Extensions.swift in Sources */,
CAD8E5C12343D885001B172A /* Random.swift in Sources */,
CAEC79D52319343100516E10 /* Logarithm.swift in Sources */,
614AD38C1FC0B134002BFE1C /* Auxiliary.swift in Sources */,
614AD3941FC0B134002BFE1C /* Trigonometric.swift in Sources */,
@ -954,6 +978,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
CAD8E5CF23441B33001B172A /* RandomTests.swift in Sources */,
CAAF5000233A701A00CC0AA7 /* LogarithmTests.swift in Sources */,
61A0AD7B1F70D22600B99FFB /* MatrixTests.swift in Sources */,
CAAF4FFC2339651600CC0AA7 /* ScalarTests.swift in Sources */,
@ -975,6 +1000,7 @@
6153945C1F762B59002A4AD2 /* Matrix.swift in Sources */,
61E930C22070B69300694FCB /* UnsafeMutableMemory.swift in Sources */,
61E930C82070BCCD00694FCB /* ArraySlice+Extensions.swift in Sources */,
CAD8E5BE2343D796001B172A /* Random.swift in Sources */,
CAEC79D22319343100516E10 /* Logarithm.swift in Sources */,
615394571F762B59002A4AD2 /* Auxiliary.swift in Sources */,
615394601F762B59002A4AD2 /* Trigonometric.swift in Sources */,

View File

@ -1037,9 +1037,9 @@ class MatrixTests: XCTestCase {
guard a.count == b.count else {
return false
}
return (zip(a, b).first { a, e -> Bool in
return !zip(a, b).contains { a, e -> Bool in
!(abs(a.0 - e.0) < accuracy && abs(a.1 - e.1) < accuracy)
}) == nil
}
}
func eigen_decomposition_trivial_generic<T: FloatingPoint & ExpressibleByFloatLiteral>(defaultAccuracy: T, eigendecompostionFn: (Matrix<T>) throws -> MatrixEigenDecompositionResult<T>) throws {

View File

@ -0,0 +1,70 @@
// Copyright © 2014-2019 the Surge contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
import XCTest
@testable import Surge
// swiftlint:disable nesting
class RandomTests: XCTestCase {
// MARK: - Box-Muller Transform
func test_box_muller_transform_float() {
typealias Scalar = Float
let lhs: [Scalar] = .randomNormalized()
let rhs: [Scalar] = .randomNormalized()
let actual: [Scalar] = { lhs, rhs in
var (lhs, rhs) = (lhs, rhs)
boxMullerTransformInPlace(&lhs, &rhs)
return lhs
}(lhs, rhs)
let expected: [Scalar] = zip(lhs, rhs).map { args in
let (lhs, rhs) = args
return sqrt(-2.0 * log(lhs)) * cos(2.0 * .pi * rhs)
}
XCTAssertEqual(actual, expected, accuracy: 1e-4)
}
func test_box_muller_transform_double() {
typealias Scalar = Double
let lhs: [Scalar] = .randomNormalized()
let rhs: [Scalar] = .randomNormalized()
let actual: [Scalar] = { lhs, rhs in
var (lhs, rhs) = (lhs, rhs)
boxMullerTransformInPlace(&lhs, &rhs)
return lhs
}(lhs, rhs)
let expected: [Scalar] = zip(lhs, rhs).map { args in
let (lhs, rhs) = args
return sqrt(-2.0 * log(lhs)) * cos(2.0 * .pi * rhs)
}
XCTAssertEqual(actual, expected, accuracy: 1e-4)
}
}