Last active
September 21, 2015 05:54
-
-
Save indragiek/10010660a8dc50df060e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// Used to lift a bounding value for a `Double` into the type system. | |
/// This is an ugly workaround for the lack of dependent types in Swift. | |
public protocol BoundingValueType { | |
static var value: Double { get } | |
} | |
/// Type that represents a bounding value of 1.0 | |
public struct _1: BoundingValueType { | |
public static var value: Double { return 1.0 } | |
} | |
/// Type that represents a bounding value of 0.0 | |
public struct _0: BoundingValueType { | |
public static var value: Double { return 0.0 } | |
} | |
/// A wrapper for a `Double` that enforces fixed boundary values. | |
/// The valid range is [LowerBound, UpperBound] | |
public struct BoundedDouble<LowerBound: BoundingValueType, UpperBound: BoundingValueType> { | |
public let value: Double | |
/// Failable initializer that only succeeds if `value` is within | |
/// the bounds specified by the parametrized types `LowerBound` | |
/// and `UpperBound` | |
public init?(value: Double) { | |
if value >= LowerBound.value && value <= UpperBound.value { | |
self.value = value | |
} else { | |
self.value = 0.0 | |
return nil | |
} | |
} | |
} | |
/// Protocol type representing a fuzzy set. Used for the purposes | |
/// of writing protocol extensions for specialized cases. | |
public protocol FuzzySetType { | |
typealias Element | |
init(membership: Element -> BoundedDouble<_0, _1>) | |
} | |
public extension FuzzySetType where Element: Equatable { | |
/// Creates a fuzzy set using a membership function that evaluates | |
/// to 1 for `element` and 0 otherwise. | |
public static func singleton(element: Element) -> FuzzySet<Element> { | |
return FuzzySet { $0 == element ? 1 : 0 } | |
} | |
} | |
public extension FuzzySetType where Element: Hashable { | |
/// Creates a fuzzy set using a membership function that evaluates | |
/// to the membership value specified for an element in `map`, and | |
/// 0 otherwise. | |
public static func pointwise(map: [Element: Double]) -> FuzzySet<Element> { | |
return FuzzySet { map[$0] ?? 0 } | |
} | |
} | |
public extension FuzzySetType where Element == Double { | |
/// Creates a fuzzy set using a triangular membership function. | |
/// `a` and `c` locate the "feet" of the triangle, and `b` locates | |
/// the peak. | |
// http://www.mathworks.com/help/fuzzy/trimf.html | |
public static func triangular(a: Element, b: Element, c: Element) -> FuzzySet<Element> { | |
return FuzzySet { x -> Element in | |
return max(min((x - a) / (b - a), (c - x) / (c - b)), 0) | |
} | |
} | |
/// Creates a fuzzy set using a trapezoidal membership function. | |
/// `a` and `d` locate the feet of the trapezoid, and `b` and `c` | |
/// specify the shoulders. | |
// http://www.mathworks.com/help/fuzzy/trapmf.html | |
public static func trapezoidal(a: Element, b: Element, c: Element, d: Element) -> FuzzySet<Element> { | |
return FuzzySet { x -> Element in | |
return max(min((x - a) / (b - a), (d - x) / (d - c)), 0) | |
} | |
} | |
/// Creates a fuzzy set using a Gaussian membership function. | |
// http://www.mathworks.com/help/fuzzy/gaussmf.html | |
public static func gaussian(c: Element, sigma: Element) -> FuzzySet<Element> { | |
return FuzzySet { exp(-pow($0 - c, 2) / (2 * pow(sigma, 2))) } | |
} | |
/// Creates a fuzzy set using a sigmoidal membership function. | |
// http://www.mathworks.com/help/fuzzy/sigmf.html | |
public static func sigmoidal(a: Element, c: Element) -> FuzzySet<Element> { | |
return FuzzySet { 1 / (1 + exp(-a * ($0 - c))) } | |
} | |
/// Creates a fuzzy set using a bell-shaped membership function. | |
/// `c` locates the center of the curve. | |
// http://www.mathworks.com/help/fuzzy/gbellmf.html | |
public static func bell(a: Element, b: Element, c: Element) -> FuzzySet<Element> { | |
return FuzzySet { 1 / (1 + pow(abs(($0 - c) / a), 2 * b)) } | |
} | |
} | |
/// A set whose elements have degrees of membership. | |
public struct FuzzySet<Element>: FuzzySetType { | |
private let membership: Element -> Double | |
/// Initializes the fuzzy set using a membership function that returns | |
/// a membership grade in the range [0.0, 1.0] for every element. | |
public init(membership: Element -> BoundedDouble<_0, _1>) { | |
self.membership = { element in | |
return membership(element).value | |
} | |
} | |
private init(_ boundedMembership: Element -> Double) { | |
self.membership = boundedMembership | |
} | |
/// Returns the empty fuzzy set, where the membership function | |
/// m(x) = 0 | |
public static func empty() -> FuzzySet<Element> { | |
return FuzzySet { _ in 0 } | |
} | |
/// Returns the universal fuzzy set, where the membership function | |
/// m(x) = 1 | |
public static func universal() -> FuzzySet<Element> { | |
return FuzzySet { _ in 1 } | |
} | |
/// Evaluates the membership function at `x` and returns the result. | |
public subscript(x: Element) -> Double { | |
return self.membership(x) | |
} | |
/// Returns a new fuzzy set that is the union of the receiver and `set`. | |
public func union(set: FuzzySet<Element>) -> FuzzySet<Element> { | |
return FuzzySet { max(self[$0], set[$0]) } | |
} | |
/// Returns a new fuzzy set that is the intersection of the receiver | |
/// and `set` | |
public func intersect(set: FuzzySet<Element>) -> FuzzySet<Element> { | |
return FuzzySet { min(self[$0], set[$0]) } | |
} | |
/// Returns a new fuzzy set that is the complement of the receiver. | |
public func complement() -> FuzzySet<Element> { | |
return FuzzySet { 1 - self[$0] } | |
} | |
/// Returns a new fuzzy set that concentrates the membership function | |
/// around points with higher membership values. | |
public func concentrate() -> FuzzySet<Element> { | |
return FuzzySet { pow(self[$0], 2) } | |
} | |
/// Opposite of `concentrate` | |
public func dilate() -> FuzzySet<Element> { | |
return FuzzySet { sqrt(self[$0]) } | |
} | |
} |
@jtbandes Wouldn't that still require runtime checks to ensure that the number isn't out of the 0.0-1.0 range?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Another solution: use
IntMax
rather thanDouble
, mapping 0.0 to.allZeros
and 1.0 to~.allZeros
. Then it's impossible to have an invalid value ;)