LM // Swiftify: LMUserOverride - phase 2.

This commit is contained in:
ShikiSuen 2022-05-03 11:43:20 +08:00
parent 8722e45dd8
commit b21a25649c
2 changed files with 92 additions and 105 deletions

View File

@ -28,11 +28,52 @@ import Foundation
extension vChewing { extension vChewing {
public class LMUserOverride { public class LMUserOverride {
// MARK: - Private Structures
var mutCapacity: Int
var mutDecayExponent: Double
var mutLRUList = [KeyObservationPair]()
var mutLRUMap: [String: KeyObservationPair] = [:]
let kDecayThreshold: Double = 1.0 / 1_048_576.0 let kDecayThreshold: Double = 1.0 / 1_048_576.0
public init(capacity: Int = 0, decayExponent: Double = 0) { struct Override {
mutCapacity = capacity var count: Int = 0
mutDecayExponent = decayExponent var timestamp: Double = 0.0
}
struct Observation {
var count: Int = 0
var overrides: [String: Override] = [:]
mutating func update(candidate: String, timestamp: Double) {
count += 1
if var neta = overrides[candidate] {
neta.timestamp = timestamp
neta.count += 1
}
}
}
struct KeyObservationPair: Equatable {
var key: String
var observation: Observation
var hashValue: Int { key.hashValue }
init(key: String, observation: Observation) {
self.key = key
self.observation = observation
}
static func == (lhs: KeyObservationPair, rhs: KeyObservationPair) -> Bool {
lhs.key == rhs.key
}
}
public init(capacity: Int = 500, decayConstant: Double = 5400.0) {
mutCapacity = abs(capacity) // Ensures that this value is always > 0.
mutDecayExponent = log(0.5) / decayConstant
} }
public func observe( public func observe(
@ -42,25 +83,24 @@ extension vChewing {
timestamp: Double timestamp: Double
) { ) {
let key = getWalkedNodesToKey(walkedNodes: walkedNodes, cursorIndex: cursorIndex) let key = getWalkedNodesToKey(walkedNodes: walkedNodes, cursorIndex: cursorIndex)
if mutLRUMap[key] == nil { guard key != "((),(),())" else { return }
let keyValuePair = KeyObservationPair(key: key, observation: Observation()) guard let map = mutLRUMap[key] else {
var observation: Observation = keyValuePair.observation var observation: Observation = .init()
observation.update(candidate: candidate, timestamp: timestamp) observation.update(candidate: candidate, timestamp: timestamp)
mutLRUList.insert(keyValuePair, at: 0)
mutLRUMap[key] = KeyObservationPair(key: key, observation: observation) mutLRUMap[key] = KeyObservationPair(key: key, observation: observation)
mutLRUList.insert(KeyObservationPair(key: key, observation: observation), at: 0)
if mutLRUList.count > mutCapacity { if mutLRUList.count > mutCapacity {
mutLRUMap[mutLRUList.reversed()[0].key] = nil mutLRUMap[mutLRUList.reversed()[0].key] = nil
mutLRUList.removeLast() mutLRUList.removeLast()
} }
} else { return
var obs = mutLRUMap[key]!.observation }
var obs = map.observation
obs.update(candidate: candidate, timestamp: timestamp) obs.update(candidate: candidate, timestamp: timestamp)
let pair = KeyObservationPair.init(key: key, observation: obs) let pair = KeyObservationPair.init(key: key, observation: obs)
mutLRUList.insert(pair, at: 0) mutLRUList.insert(pair, at: 0)
} }
}
public func suggest( public func suggest(
walkedNodes: [Megrez.NodeAnchor], walkedNodes: [Megrez.NodeAnchor],
@ -71,6 +111,12 @@ extension vChewing {
guard let keyValuePair = mutLRUMap[key] else { guard let keyValuePair = mutLRUMap[key] else {
return "" return ""
} }
IME.prtDebugIntel("Suggest - A: \(key)")
IME.prtDebugIntel("Suggest - B: \(keyValuePair.key)")
guard key != "((),(),())" else { return "" }
let observation = keyValuePair.observation let observation = keyValuePair.observation
var candidate = "" var candidate = ""
@ -119,104 +165,52 @@ extension vChewing {
func getWalkedNodesToKey( func getWalkedNodesToKey(
walkedNodes: [Megrez.NodeAnchor], cursorIndex: Int walkedNodes: [Megrez.NodeAnchor], cursorIndex: Int
) -> String { ) -> String {
var s = "" var strOutput = ""
var n: [Megrez.NodeAnchor] = [] var arrNodes: [Megrez.NodeAnchor] = []
var ll = 0 var intLength = 0
for i in walkedNodes { for nodeNeta in walkedNodes {
let nn = i arrNodes.append(nodeNeta)
n.append(nn) intLength += nodeNeta.spanningLength
ll += nn.spanningLength if intLength >= cursorIndex {
if ll >= cursorIndex {
break break
} }
} }
var r: [Megrez.NodeAnchor] = [] // .reversed 使 Swift
r.append(contentsOf: n.reversed()) //
var arrNodesReversed: [Megrez.NodeAnchor] = []
arrNodesReversed.append(contentsOf: arrNodes.reversed())
if r.isEmpty { if arrNodesReversed.isEmpty {
return "" return ""
} }
if let theAnchor = r.first, theAnchor.node != nil { var strCurrent = "()"
let theNode = theAnchor.node! var strPrev = "()"
let current = theNode.currentKeyValue().key var strAnterior = "()"
r.removeFirst()
s = "" // s for (theIndex, theAnchor) in arrNodesReversed.enumerated() {
if !r.isEmpty { if strCurrent != "()", let nodeCurrent = theAnchor.node {
let value = theNode.currentKeyValue().value let keyCurrent = nodeCurrent.currentKeyValue().key
if isEndingPunctuation(value: value) { let valCurrent = nodeCurrent.currentKeyValue().value
s = "()" strCurrent = "(\(keyCurrent), \(valCurrent))"
r = [] if let nodePrev = arrNodesReversed[theIndex + 1].node {
} else { let keyPrev = nodePrev.currentKeyValue().key
s = "(\(theNode.currentKeyValue().key),\(value))" let valPrev = nodePrev.currentKeyValue().value
r.removeFirst() strPrev = "(\(keyPrev), \(valPrev))"
} }
} else { if let nodeAnterior = arrNodesReversed[theIndex + 2].node {
s = "()" let keyAnterior = nodeAnterior.currentKeyValue().key
} let valAnterior = nodeAnterior.currentKeyValue().value
let prev = s strAnterior = "(\(keyAnterior), \(valAnterior))"
s = ""
if !r.isEmpty {
let value = theNode.currentKeyValue().value
if isEndingPunctuation(value: value) {
s = "()"
r = []
} else {
s = "(\(theNode.currentKeyValue().key),\(value))"
r.removeFirst()
}
} else {
s = "()"
}
let anterior = s
s = "(\(anterior),\(prev),\(current))"
}
return s
}
// MARK: - Private Structures
var mutCapacity: Int
var mutDecayExponent: Double
var mutLRUList = [KeyObservationPair]()
var mutLRUMap: [String: KeyObservationPair] = [:]
struct Override {
var count: Int = 0
var timestamp: Double = 0.0
}
struct Observation {
var count: Int = 0
var overrides: [String: Override] = [:]
mutating func update(candidate: String, timestamp: Double) {
count += 1
if var neta = overrides[candidate] {
neta.timestamp = timestamp
neta.count += 1
} }
break //
} }
} }
struct KeyObservationPair: Equatable { strOutput = "(\(strAnterior),\(strPrev),\(strCurrent))"
var key: String
var observation: Observation
var hashValue: Int { key.hashValue } return strOutput
init(key: String, observation: Observation) {
self.key = key
self.observation = observation
}
static func == (lhs: KeyObservationPair, rhs: KeyObservationPair) -> Bool {
lhs.key == rhs.key
}
} }
} }
} }

View File

@ -31,17 +31,10 @@ import Cocoa
/// ///
/// mgrLangModel /// mgrLangModel
private let kUserOverrideModelCapacity: Int = 500
private let kObservedOverrideHalflife: Double = 5400.0
private var gLangModelCHS = vChewing.LMInstantiator() private var gLangModelCHS = vChewing.LMInstantiator()
private var gLangModelCHT = vChewing.LMInstantiator() private var gLangModelCHT = vChewing.LMInstantiator()
private var gUserOverrideModelCHS = vChewing.LMUserOverride( private var gUserOverrideModelCHS = vChewing.LMUserOverride()
capacity: kUserOverrideModelCapacity, decayExponent: kObservedOverrideHalflife private var gUserOverrideModelCHT = vChewing.LMUserOverride()
)
private var gUserOverrideModelCHT = vChewing.LMUserOverride(
capacity: kUserOverrideModelCapacity, decayExponent: kObservedOverrideHalflife
)
class mgrLangModel: NSObject { class mgrLangModel: NSObject {
/// fileprivate /// fileprivate