vChewing-macOS/Packages/vChewing_Megrez/Sources/Megrez/2_Walker.swift

108 lines
3.5 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Swiftified by (c) 2022 and onwards The vChewing Project (MIT License).
// Rebranded from (c) Lukhnos Liu's C++ library "Gramambular 2" (MIT License).
// ====================
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
extension Megrez.Compositor {
///
/// 使 Cormen 2001
///
///
/// `G = (V, E)` `O(|V|+|E|)` `G`
/// 使
/// - Returns:
@discardableResult public mutating func walk() -> ([Node], Bool) {
var result = [Node]()
defer {
walkedNodes = result
updateCursorJumpingTables(walkedNodes)
}
guard !spans.isEmpty else { return (result, true) }
var vertexSpans = [VertexSpan]()
for _ in spans {
vertexSpans.append(.init())
}
for (i, span) in spans.enumerated() {
for j in 1...span.maxLength {
if let p = span.nodeOf(length: j) {
vertexSpans[i].append(.init(node: p))
}
}
}
let terminal = Vertex(node: .init(keyArray: ["_TERMINAL_"], keySeparator: separator))
for (i, vertexSpan) in vertexSpans.enumerated() {
for vertex in vertexSpan {
let nextVertexPosition = i + vertex.node.spanLength
if nextVertexPosition == vertexSpans.count {
vertex.edges.append(terminal)
continue
}
for nextVertex in vertexSpans[nextVertexPosition] {
vertex.edges.append(nextVertex)
}
}
}
let root = Vertex(node: .init(keyArray: ["_ROOT_"], keySeparator: separator))
root.distance = 0
root.edges.append(contentsOf: vertexSpans[0])
var ordered: [Vertex] = topologicalSort(root: root)
for (j, neta) in ordered.reversed().enumerated() {
for (k, _) in neta.edges.enumerated() {
relax(u: neta, v: &neta.edges[k])
}
ordered[j] = neta
}
var walked = [Node]()
var totalKeyLength = 0
var it = terminal
while let itPrev = it.prev {
walked.append(itPrev.node)
it = itPrev
totalKeyLength += it.node.spanLength
}
guard totalKeyLength == keys.count else {
print("!!! ERROR A")
return (result, false)
}
guard walked.count >= 2 else {
print("!!! ERROR B")
return (result, false)
}
walked = walked.reversed()
walked.removeFirst()
result = walked
return (result, true)
}
}
// MARK: - Stable Sort Extension
// Reference: https://stackoverflow.com/a/50545761/4162914
extension Sequence {
/// Return a stable-sorted collection.
///
/// - Parameter areInIncreasingOrder: Return nil when two element are equal.
/// - Returns: The sorted collection.
fileprivate func stableSorted(
by areInIncreasingOrder: (Element, Element) throws -> Bool
)
rethrows -> [Element]
{
try enumerated()
.sorted { a, b -> Bool in
try areInIncreasingOrder(a.element, b.element)
|| (a.offset < b.offset && !areInIncreasingOrder(b.element, a.element))
}
.map(\.element)
}
}