Guest User

Untitled

a guest
Jul 19th, 2018
58
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.11 KB | None | 0 0
  1. import Foundation
  2.  
  3. // MARK: - Definitions -
  4.  
  5. public typealias Vector<T : Hashable> = [T : Int]
  6.  
  7. public typealias Matrix<T : Hashable> = [T : Vector<T>]
  8.  
  9. public enum DecisionProcess {
  10. case predict
  11. case random
  12. case weightedRandom
  13. }
  14.  
  15. // MARK: - Type -
  16.  
  17. public struct MarkovModel<T : Hashable> {
  18.  
  19. // MARK: - Properties
  20.  
  21. public private(set) var chain: Matrix<T>
  22.  
  23. // MARK: - Constructors
  24.  
  25. /// - Complexity: O(n), where *n* is the length of the **transitions**.
  26. public init(transitions: [T]) {
  27. chain = transitions.makeTransitionsMatrix()
  28. }
  29.  
  30. /// - Complexity: O(n), where *n* is the length of the **transitions**.
  31. public static func process(transitions: [T], completion: (Matrix<T>) -> Void) {
  32. completion(transitions.makeTransitionsMatrix())
  33. }
  34. }
  35.  
  36. // MARK: - Matrix - Array
  37.  
  38. public extension Matrix where Value == Vector<Key> {
  39.  
  40. /// - Complexity: O(n log n), where *n* is the matrix's size
  41. public var uniqueStates: [Key] {
  42. var result = Set<Key>(keys)
  43. forEach { result.formUnion(Array($0.value.keys)) }
  44. return Array(result)
  45. }
  46.  
  47. /// - Complexity: O(1), regardless the matrix's size.
  48. public func probabilities(given: Key) -> Vector<Key> {
  49. return self[given] ?? [:]
  50. }
  51.  
  52. /// - Complexity: O(n), where *n* is the length of the possible transitions for the given **states**.
  53. public func next(given: Key, process: DecisionProcess = .predict) -> Key? {
  54. guard let values = self[given] else {
  55. return nil
  56. }
  57.  
  58. let column = Array(values)
  59.  
  60. switch process {
  61. case .predict:
  62. return values.max(by: { $0.value < $1.value })?.key
  63. case .random:
  64. return column.map({ $0.key }).randomElement
  65. case .weightedRandom:
  66. let probabilities = column.map { $0.value }
  67. return column[probabilities.weightedRandomIndex].key
  68. }
  69. }
  70. }
  71.  
  72. // MARK: - Extension - Array
  73.  
  74. public extension Array where Element == IntegerLiteralType {
  75.  
  76. /// - Complexity: O(n), where *n* is the count of this array.
  77. public var weightedRandomIndex: Index {
  78.  
  79. let sum = reduce(0, +)
  80. let max = UInt32.max
  81. let random = Element(Float(sum) * Float(arc4random_uniform(max)) / Float(max))
  82. var accumulated = Element(0.0)
  83. let first = enumerated().first {
  84. accumulated += $1
  85. return random < accumulated
  86. }
  87.  
  88. return first?.offset ?? count - 1
  89. }
  90. }
  91.  
  92. // MARK: - Extension - Array
  93.  
  94. extension Array where Element : Hashable {
  95.  
  96. /// - Complexity: O(1), regardless the matrix's size.
  97. var randomElement: Element? {
  98.  
  99. if isEmpty { return nil }
  100.  
  101. let index = Int(arc4random_uniform(UInt32(count)))
  102.  
  103. return self[index]
  104. }
  105.  
  106. /// - Complexity: O(n), where **n** is the total length of all transitions.
  107. func makeTransitionsMatrix() -> Matrix<Element> {
  108.  
  109. var changesMatrix = Matrix<Element>()
  110.  
  111. guard var old = first else {
  112. return changesMatrix
  113. }
  114.  
  115. suffix(from: 1).forEach { nextValue in
  116. var chain = changesMatrix[old] ?? Vector<Element>()
  117. chain[nextValue] = 1 + (chain[nextValue] ?? 0)
  118. changesMatrix[old] = chain
  119. old = nextValue
  120. }
  121.  
  122. return changesMatrix
  123. }
  124. }
  125.  
  126. MarkovModel.process(transitions: [1,2,3,2]) { matrix in
  127. print(matrix)
  128. }
  129.  
  130. let model = MarkovModel(transitions: ["A", "B", "A", "C"])
  131. print(model.chain)
  132. print(model.chain.next(given: "A")!)
Add Comment
Please, Sign In to add comment