[Performance] LOUDSのinit処理を高速化 (#30)

* simplify calculation

* cleanup

* add code fro debug

* fix bug

* cleanup

* cleanup

* add binary search

* cleanup binary search

* cleanup binary search

* cleanup init

* cleanup init

* debugging: flatten indices

* flatten indices
This commit is contained in:
Miwa / Ensan
2024-01-07 15:48:19 +09:00
committed by GitHub
parent 1bbb1ec03e
commit f2c5c3c58d

View File

@@ -15,7 +15,11 @@ struct LOUDS: Sendable {
private static let uExp = 6
private let bits: [Unit]
private let char2nodeIndices: [[Int]]
/// indexflattenArray
/// - seealso: flatChar2nodeIndicesIndex
private let flatChar2nodeIndices: [Int]
/// 256Array`flatChar2nodeIndices[flatChar2nodeIndicesIndex[char - 1] ..< flatChar2nodeIndicesIndex[char]]``nodeIndices`
private let flatChar2nodeIndicesIndex: [Int]
/// 01
///
/// LOUDS4GB`UInt32`
@@ -23,12 +27,42 @@ struct LOUDS: Sendable {
@inlinable init(bytes: [UInt64], nodeIndex2ID: [UInt8]) {
self.bits = bytes
self.char2nodeIndices = nodeIndex2ID.enumerated().reduce(into: .init(repeating: [], count: 1 << 8)) { list, data in
list[Int(data.element)].append(data.offset)
// flatChar2nodeIndicesIndex
// charnodeIndices
var flatChar2nodeIndicesIndex = [Int](repeating: 0, count: 256)
flatChar2nodeIndicesIndex.withUnsafeMutableBufferPointer { buffer in
for value in nodeIndex2ID {
buffer[Int(value)] += 1
}
//
for i in 1 ..< 256 {
buffer[i] = buffer[i - 1] + buffer[i]
}
}
self.rankLarge = bytes.reduce(into: [0]) {
$0.append($0.last! &+ UInt32(Self.unit &- $1.nonzeroBitCount))
// flatChar2nodeIndices
// flatChar2nodeIndicesIndexcountsindex
var counts = [Int](repeating: 0, count: 256)
self.flatChar2nodeIndices = counts.withUnsafeMutableBufferPointer { countsBuffer in
var flatChar2nodeIndices = [Int](repeating: 0, count: nodeIndex2ID.count)
for (i, value) in zip(nodeIndex2ID.indices, nodeIndex2ID) {
if value == .zero {
flatChar2nodeIndices[countsBuffer[Int(value)]] = i
} else {
flatChar2nodeIndices[flatChar2nodeIndicesIndex[Int(value) - 1] + countsBuffer[Int(value)]] = i
}
countsBuffer[Int(value)] += 1
}
return flatChar2nodeIndices
}
self.flatChar2nodeIndicesIndex = consume flatChar2nodeIndicesIndex
var rankLarge: [UInt32] = .init(repeating: 0, count: bytes.count + 1)
rankLarge.withUnsafeMutableBufferPointer { buffer in
for (i, byte) in zip(bytes.indices, bytes) {
buffer[i + 1] = buffer[i] &+ UInt32(Self.unit &- byte.nonzeroBitCount)
}
}
self.rankLarge = consume rankLarge
}
/// parentNodeIndex01Index
@@ -43,34 +77,33 @@ struct LOUDS: Sendable {
// rankLarge0dif
// left
// startIndexbitsindex `i`
var left = (parentNodeIndex >> Self.uExp) &- 1
while true {
let dif = parentNodeIndex &- Int(self.rankLarge[Int(left) &+ 1])
if dif >= Self.unit {
left &+= dif >> Self.uExp
var left = parentNodeIndex >> Self.uExp
var right = self.rankLarge.endIndex - 1
var i = self.rankLarge.endIndex
while left <= right {
let mid = (left + right) / 2
if self.rankLarge[mid] >= parentNodeIndex {
i = mid
right = mid - 1
} else {
break
left = mid + 1
}
}
var i: Int?
for index in left &+ 1 ..< self.bits.endIndex where self.rankLarge[index &+ 1] >= parentNodeIndex {
i = index
break
}
guard let i else {
guard i != self.rankLarge.endIndex else {
return 0 ..< 0
}
//
// parentNodeIndex0`k`
let byte = self.bits[i]
var k = 0
for _ in 0 ..< parentNodeIndex - Int(self.rankLarge[i]) {
k = (~(byte << k)).leadingZeroBitCount &+ k &+ 1
}
let start = (i << Self.uExp) &+ k &- parentNodeIndex &+ 1
// parentNodeIndex0i
if self.rankLarge[i &+ 1] == parentNodeIndex {
return self.bits.withUnsafeBufferPointer {(buffer: UnsafeBufferPointer<Unit>) -> Range<Int> in
i -= 1
return self.bits.withUnsafeBufferPointer {(buffer: UnsafeBufferPointer<Unit>) -> Range<Int> in
//
// parentNodeIndex0`k`
let byte = buffer[i]
var k = 0
for _ in 0 ..< parentNodeIndex - Int(self.rankLarge[i]) {
k = (~(byte << k)).leadingZeroBitCount &+ k &+ 1
}
let start = (i << Self.uExp) &+ k &- parentNodeIndex &+ 1
// parentNodeIndex0i
if self.rankLarge[i &+ 1] == parentNodeIndex {
var j = i &+ 1
while buffer[j] == Unit.max {
j &+= 1
@@ -81,13 +114,13 @@ struct LOUDS: Sendable {
let byte2 = buffer[j]
let a = (~byte2).leadingZeroBitCount % Self.unit
return start ..< (j << Self.uExp) &+ a &- parentNodeIndex &+ 1
} else {
// dif0k0
// k=1
// Ex. 1011_1101 => 0111_1010 => 1000_0101 => 1 => 2
let a = ((~(byte << k)).leadingZeroBitCount &+ k) % Self.unit
return start ..< (i << Self.uExp) &+ a &- parentNodeIndex &+ 1
}
} else {
// dif0k0
// k=1
// Ex. 1011_1101 => 0111_1010 => 1000_0101 => 1 => 2
let a = ((~(byte << k)).leadingZeroBitCount &+ k) % Self.unit
return start ..< (i << Self.uExp) &+ a &- parentNodeIndex &+ 1
}
}
@@ -96,7 +129,12 @@ struct LOUDS: Sendable {
@inlinable func searchCharNodeIndex(from parentNodeIndex: Int, char: UInt8) -> Int? {
// char2nodeIndices調
let childNodeIndices = self.childNodeIndices(from: parentNodeIndex)
let nodeIndices = self.char2nodeIndices[Int(char)]
let nodeIndices: ArraySlice<Int> = if char == .zero {
self.flatChar2nodeIndices[0 ..< self.flatChar2nodeIndicesIndex[Int(char)]]
} else {
self.flatChar2nodeIndices[self.flatChar2nodeIndicesIndex[Int(char - 1)] ..< self.flatChar2nodeIndicesIndex[Int(char)]]
}
var left = nodeIndices.startIndex
var right = nodeIndices.endIndex
while left < right {