// // all.swift // Keyboard // // Created by ensan on 2020/09/14. // Copyright © 2020 ensan. All rights reserved. // import Foundation import SwiftUtils extension Kana2Kanji { /// カナを漢字に変換する関数, 前提はなくかな列が与えられた場合。 /// - Parameters: /// - inputData: 入力データ。 /// - N_best: N_best。 /// - Returns: /// 変換候補。 /// ### 実装状況 /// (0)多用する変数の宣言。 /// /// (1)まず、追加された一文字に繋がるノードを列挙する。 /// /// (2)次に、計算済みノードから、(1)で求めたノードにつながるようにregisterして、N_bestを求めていく。 /// /// (3)(1)のregisterされた結果をresultノードに追加していく。この際EOSとの連接計算を行っておく。 /// /// (4)ノードをアップデートした上で返却する。 func kana2lattice_all(_ inputData: ComposingText, N_best: Int, needTypoCorrection: Bool) -> (result: LatticeNode, lattice: Lattice) { debug("新規に計算を行います。inputされた文字列は\(inputData.input.count)文字分の\(inputData.convertTarget)") let count: Int = inputData.input.count let result: LatticeNode = LatticeNode.EOSNode let nodes: [[LatticeNode]] = (.zero ..< count).map {dicdataStore.getLOUDSDataInRange(inputData: inputData, from: $0, needTypoCorrection: needTypoCorrection)} // 「i文字目から始まるnodes」に対して for (i, nodeArray) in nodes.enumerated() { // それぞれのnodeに対して for node in nodeArray { if node.prevs.isEmpty { continue } if self.dicdataStore.shouldBeRemoved(data: node.data) { continue } // 生起確率を取得する。 let wValue: PValue = node.data.value() if i == 0 { // valuesを更新する node.values = node.prevs.map {$0.totalValue + wValue + self.dicdataStore.getCCValue($0.data.rcid, node.data.lcid)} } else { // valuesを更新する node.values = node.prevs.map {$0.totalValue + wValue} } // 変換した文字数 let nextIndex: Int = node.inputRange.endIndex // 文字数がcountと等しい場合登録する if nextIndex == count { for index in node.prevs.indices { let newnode: RegisteredNode = node.getRegisteredNode(index, value: node.values[index]) result.prevs.append(newnode) } } else { self.updateNextNodes(with: node, nextNodes: nodes[nextIndex], nBest: N_best) } } } return (result: result, lattice: Lattice(nodes: nodes)) } /// N-Best計算を高速に実行しつつ、遷移先ノードを更新する func updateNextNodes(with node: LatticeNode, nextNodes: [LatticeNode], nBest: Int) { for nextnode in nextNodes { if self.dicdataStore.shouldBeRemoved(data: nextnode.data) { continue } // クラスの連続確率を計算する。 let ccValue: PValue = self.dicdataStore.getCCValue(node.data.rcid, nextnode.data.lcid) // nodeの持っている全てのprevnodeに対して for (index, value) in node.values.enumerated() { let newValue: PValue = ccValue + value // 追加すべきindexを取得する let lastindex: Int = (nextnode.prevs.lastIndex(where: {$0.totalValue >= newValue}) ?? -1) + 1 if lastindex == nBest { continue } let newnode: RegisteredNode = node.getRegisteredNode(index, value: newValue) // カウントがオーバーしている場合は除去する if nextnode.prevs.count >= nBest { nextnode.prevs.removeLast() } // removeしてからinsertした方が速い (insertはO(N)なので) nextnode.prevs.insert(newnode, at: lastindex) } } } }