From 276f593f429c0a57ce6a53314f6a6bcb6b04d245 Mon Sep 17 00:00:00 2001 From: Anthony Platanios Date: Sun, 13 Jan 2019 11:12:24 -0500 Subject: [PATCH 1/4] Added support for sampling from a Beta distribution. --- stdlib/public/TensorFlow/Random.swift | 129 ++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/stdlib/public/TensorFlow/Random.swift b/stdlib/public/TensorFlow/Random.swift index 74108ad409be2..8b2b3020f5cd6 100644 --- a/stdlib/public/TensorFlow/Random.swift +++ b/stdlib/public/TensorFlow/Random.swift @@ -171,3 +171,132 @@ public final class NormalDistribution return mean + standardDeviation * normal01 } } + +@_fixed_layout +public final class BetaDistribution { + public let α: Float + public let β: Float + private let uniformDistribution = UniformFloatingPointDistribution() + + public init(α: Float = 0, β: Float = 1) { + self.α = α + self.β = β + } + + public func next(using rng: inout G) -> Float { + // Generate a sample using Cheng's sampling algorithm from: + // R. C. H. Cheng, "Generating beta variates with nonintegral shape + // parameters.". Communications of the ACM, 21, 317-322, 1978. + let a = min(α, β) + let b = max(α, β) + if a > 1 { + return BetaDistribution.chengsAlgorithmBB(α, a, b, using: &rng) + } else { + return BetaDistribution.chengsAlgorithmBC(α, b, a, using: &rng) + } + } + + /// Returns one sample from a Beta(α, β) distribution using Cheng's BB + /// algorithm, when both α and β are greater than 1. + /// + /// - Parameters: + /// - α: First Beta distribution shape parameter. + /// - a: `min(α, β)`, where α and β are the Beta distribution parameters. + /// - b: `max(α, β)`, where α and β are the Beta distribution parameters. + /// - rng: Random number generator. + /// + /// - Returns: Sample obtained using Cheng's BB algorithm. + private static func chengsAlgorithmBB( + _ α: Float, + _ a: Float, + _ b: Float, + using rng: inout G + ) -> Float { + let alpha = a + b + let beta = sqrt((alpha - 2) / (2 * a * b - alpha)) + let gamma = a + 1 / beta + + var r: Float = 0.0 + var w: Float = 0.0 + var t: Float = 0.0 + + repeat { + let u1 = Float.random(in: 0.0...1.0, using: &rng) + let u2 = Float.random(in: 0.0...1.0, using: &rng) + let v = beta * (log(u1) - log1p(-u1)) + r = gamma * v - 1.3862944 + let z = u1 * u1 * u2 + w = a * exp(v) + + let s = a + r - w + if s + 2.609438 >= 5 * z { + break + } + + t = log(z) + if (s >= t) { + break + } + } while r + alpha * (log(alpha) - log(b + w)) < t + + w = min(w, Float.greatestFiniteMagnitude) + return a == α ? w / (b + w) : b / (b + w) + } + + /// Returns one sample from a Beta(α, β) distribution using Cheng's BC + /// algorithm, when at least one of α and β is less than 1. + /// + /// - Parameters: + /// - α: First Beta distribution shape parameter. + /// - a: `max(α, β)`, where α and β are the Beta distribution parameters. + /// - b: `min(α, β)`, where α and β are the Beta distribution parameters. + /// - rng: Random number generator. + /// + /// - Returns: Sample obtained using Cheng's BB algorithm. + private static func chengsAlgorithmBC( + _ α: Float, + _ a: Float, + _ b: Float, + using rng: inout G + ) -> Float { + let alpha = a + b + let beta = 1 / b + let delta = 1 + a - b + let k1 = delta * (0.0138889 + 0.0416667 * b) / (a * beta - 0.777778) + let k2 = 0.25 + (0.5 + 0.25 / delta) * b + + var w: Float = 0.0 + + while (true) { + let u1 = Float.random(in: 0.0...1.0, using: &rng) + let u2 = Float.random(in: 0.0...1.0, using: &rng) + let y = u1 * u2 + let z = u1 * y + + if u1 < 0.5 { + if 0.25 * u2 + z - y >= k1 { + continue + } + } else { + if z <= 0.25 { + let v = beta * (log(u1) - log1p(-u1)) + w = a * exp(v) + break + } + + if z >= k2 { + continue + } + } + + let v = beta * (log(u1) - log1p(-u1)) + w = a * exp(v) + if alpha * (log(alpha) - log(b + 1) + v) - 1.3862944 >= log(z) { + break + } + } + + w = min(w, Float.greatestFiniteMagnitude) + return a == α ? w / (b + w) : b / (b + w) + } +} From 15069db4f349ccf77673a11158784710ef6409fe Mon Sep 17 00:00:00 2001 From: Anthony Platanios Date: Sun, 13 Jan 2019 11:28:25 -0500 Subject: [PATCH 2/4] Formatting edits. --- stdlib/public/TensorFlow/Random.swift | 50 +++++++++++++-------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/stdlib/public/TensorFlow/Random.swift b/stdlib/public/TensorFlow/Random.swift index 8b2b3020f5cd6..28c85482de0dc 100644 --- a/stdlib/public/TensorFlow/Random.swift +++ b/stdlib/public/TensorFlow/Random.swift @@ -174,40 +174,40 @@ public final class NormalDistribution @_fixed_layout public final class BetaDistribution { - public let α: Float - public let β: Float + public let alpha: Float + public let beta: Float private let uniformDistribution = UniformFloatingPointDistribution() - public init(α: Float = 0, β: Float = 1) { - self.α = α - self.β = β + public init(alpha: Float = 0, beta: Float = 1) { + self.alpha = alpha + self.beta = beta } public func next(using rng: inout G) -> Float { // Generate a sample using Cheng's sampling algorithm from: // R. C. H. Cheng, "Generating beta variates with nonintegral shape // parameters.". Communications of the ACM, 21, 317-322, 1978. - let a = min(α, β) - let b = max(α, β) + let a = min(alpha, beta) + let b = max(alpha, beta) if a > 1 { - return BetaDistribution.chengsAlgorithmBB(α, a, b, using: &rng) + return BetaDistribution.chengsAlgorithmBB(alpha, a, b, using: &rng) } else { - return BetaDistribution.chengsAlgorithmBC(α, b, a, using: &rng) + return BetaDistribution.chengsAlgorithmBC(alpha, b, a, using: &rng) } } - /// Returns one sample from a Beta(α, β) distribution using Cheng's BB - /// algorithm, when both α and β are greater than 1. + /// Returns one sample from a Beta(alpha, beta) distribution using Cheng's BB + /// algorithm, when both alpha and beta are greater than 1. /// /// - Parameters: - /// - α: First Beta distribution shape parameter. - /// - a: `min(α, β)`, where α and β are the Beta distribution parameters. - /// - b: `max(α, β)`, where α and β are the Beta distribution parameters. + /// - alpha: First Beta distribution shape parameter. + /// - a: `min(alpha, beta)`. + /// - b: `max(alpha, beta)`. /// - rng: Random number generator. /// /// - Returns: Sample obtained using Cheng's BB algorithm. private static func chengsAlgorithmBB( - _ α: Float, + _ alpha: Float, _ a: Float, _ b: Float, using rng: inout G @@ -234,27 +234,27 @@ public final class BetaDistribution { } t = log(z) - if (s >= t) { + if s >= t { break } } while r + alpha * (log(alpha) - log(b + w)) < t w = min(w, Float.greatestFiniteMagnitude) - return a == α ? w / (b + w) : b / (b + w) + return a == alpha ? w / (b + w) : b / (b + w) } - /// Returns one sample from a Beta(α, β) distribution using Cheng's BC - /// algorithm, when at least one of α and β is less than 1. + /// Returns one sample from a Beta(alpha, beta) distribution using Cheng's BC + /// algorithm, when at least one of alpha and beta is less than 1. /// /// - Parameters: - /// - α: First Beta distribution shape parameter. - /// - a: `max(α, β)`, where α and β are the Beta distribution parameters. - /// - b: `min(α, β)`, where α and β are the Beta distribution parameters. + /// - alpha: First Beta distribution shape parameter. + /// - a: `max(alpha, beta)`. + /// - b: `min(alpha, beta)`. /// - rng: Random number generator. /// /// - Returns: Sample obtained using Cheng's BB algorithm. private static func chengsAlgorithmBC( - _ α: Float, + _ alpha: Float, _ a: Float, _ b: Float, using rng: inout G @@ -267,7 +267,7 @@ public final class BetaDistribution { var w: Float = 0.0 - while (true) { + while true { let u1 = Float.random(in: 0.0...1.0, using: &rng) let u2 = Float.random(in: 0.0...1.0, using: &rng) let y = u1 * u2 @@ -297,6 +297,6 @@ public final class BetaDistribution { } w = min(w, Float.greatestFiniteMagnitude) - return a == α ? w / (b + w) : b / (b + w) + return a == alpha ? w / (b + w) : b / (b + w) } } From 773ed1c489c249c65b2bf72c9d7dbf48b7d4aaa3 Mon Sep 17 00:00:00 2001 From: Anthony Platanios Date: Sun, 13 Jan 2019 11:34:38 -0500 Subject: [PATCH 3/4] Bug fix. --- stdlib/public/TensorFlow/Random.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stdlib/public/TensorFlow/Random.swift b/stdlib/public/TensorFlow/Random.swift index 28c85482de0dc..8975e92597653 100644 --- a/stdlib/public/TensorFlow/Random.swift +++ b/stdlib/public/TensorFlow/Random.swift @@ -207,7 +207,7 @@ public final class BetaDistribution { /// /// - Returns: Sample obtained using Cheng's BB algorithm. private static func chengsAlgorithmBB( - _ alpha: Float, + _ alpha0: Float, _ a: Float, _ b: Float, using rng: inout G @@ -240,7 +240,7 @@ public final class BetaDistribution { } while r + alpha * (log(alpha) - log(b + w)) < t w = min(w, Float.greatestFiniteMagnitude) - return a == alpha ? w / (b + w) : b / (b + w) + return a == alpha0 ? w / (b + w) : b / (b + w) } /// Returns one sample from a Beta(alpha, beta) distribution using Cheng's BC @@ -254,7 +254,7 @@ public final class BetaDistribution { /// /// - Returns: Sample obtained using Cheng's BB algorithm. private static func chengsAlgorithmBC( - _ alpha: Float, + _ alpha0: Float, _ a: Float, _ b: Float, using rng: inout G @@ -297,6 +297,6 @@ public final class BetaDistribution { } w = min(w, Float.greatestFiniteMagnitude) - return a == alpha ? w / (b + w) : b / (b + w) + return a == alpha0 ? w / (b + w) : b / (b + w) } } From c5d03a87fdceb746321d2dc727d70e20979d8654 Mon Sep 17 00:00:00 2001 From: Richard Wei Date: Wed, 16 Jan 2019 18:45:20 -0800 Subject: [PATCH 4/4] Update Random.swift --- stdlib/public/TensorFlow/Random.swift | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/stdlib/public/TensorFlow/Random.swift b/stdlib/public/TensorFlow/Random.swift index 8975e92597653..224f39c3f190c 100644 --- a/stdlib/public/TensorFlow/Random.swift +++ b/stdlib/public/TensorFlow/Random.swift @@ -200,10 +200,10 @@ public final class BetaDistribution { /// algorithm, when both alpha and beta are greater than 1. /// /// - Parameters: - /// - alpha: First Beta distribution shape parameter. - /// - a: `min(alpha, beta)`. - /// - b: `max(alpha, beta)`. - /// - rng: Random number generator. + /// - alpha: First Beta distribution shape parameter. + /// - a: `min(alpha, beta)`. + /// - b: `max(alpha, beta)`. + /// - rng: Random number generator. /// /// - Returns: Sample obtained using Cheng's BB algorithm. private static func chengsAlgorithmBB( @@ -283,7 +283,6 @@ public final class BetaDistribution { w = a * exp(v) break } - if z >= k2 { continue }