fix: forget memoryの実装を「粗い」チェックに変更し、表層形の一致のみで判断するようにした

This commit is contained in:
Miwa / Ensan
2025-06-02 22:32:17 +09:00
parent 503c9171b2
commit 2569d8475e
3 changed files with 79 additions and 4 deletions

View File

@ -226,6 +226,7 @@ struct LongTermLearningMemory {
debug("LongTermLearningMemory merge entryCount", entryCount, ltMetadata.count)
let forgetTargetWords = forgetTargets.map { $0.word }
// loudstxt3
for loudstxtIndex in 0 ..< Int(entryCount) / txtFileSplit + 1 {
let loudstxtData: Data
@ -262,8 +263,8 @@ struct LongTermLearningMemory {
var newMetadata: [MetadataElement] = []
assert(elements.count == metadata.count, "elements count and metadata count must be equal.")
for (dicdataElement, metadataElement) in zip(elements, metadata) {
//
if forgetTargets.contains(dicdataElement) {
//
if forgetTargetWords.contains(dicdataElement.word) {
debug("LongTermLearningMemory merge stopped because it is a forget target", dicdataElement)
continue
}
@ -564,8 +565,10 @@ struct TemporalLearningMemoryTrie {
}
}
//
// dataIndices(dicdata)
nodes[index].dataIndices.removeAll(where: {self.dicdata[$0] == dicdataElement})
//
nodes[index].dataIndices.removeAll {
self.dicdata[$0].word == dicdataElement.word
}
return true
}

View File

@ -99,5 +99,46 @@ final class LearningMemoryTests: XCTestCase {
let dicdata2 = dicdataStore.getDicdataFromLoudstxt3(identifier: "memory", indices: indices2)
XCTAssertFalse(dicdata2.contains { $0.word == element.word && $0.ruby == element.ruby })
}
func testCoarseForgetMemory() throws {
// ForgetMemory
let dir = FileManager.default.temporaryDirectory.appendingPathComponent("LearningManagerPersistence-\(UUID().uuidString)", isDirectory: true)
try FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
defer { try? FileManager.default.removeItem(at: dir) }
let options = self.getOptionsForMemoryTest(memoryDirectoryURL: dir)
let manager = LearningManager()
_ = manager.setRequestOptions(options)
let element = DicdataElement(word: "テスト", ruby: "テスト", cid: CIDData..cid, mid: MIDData..mid, value: -10)
manager.update(data: [element])
let differentCidElement = DicdataElement(word: "テスト", ruby: "テスト", cid: CIDData..cid, mid: MIDData..mid, value: -10)
manager.update(data: [differentCidElement])
manager.save()
let dicdataStore = DicdataStore(requestOptions: options)
dicdataStore.sendToDicdataStore(.setRequestOptions(options))
let charIDs = "テスト".map { dicdataStore.character2charId($0) }
let indices = dicdataStore.perfectMatchLOUDS(query: "memory", charIDs: charIDs)
let dicdata = dicdataStore.getDicdataFromLoudstxt3(identifier: "memory", indices: indices)
XCTAssertFalse(dicdata.isEmpty)
XCTAssertEqual(dicdata.count { $0.word == element.word && $0.ruby == element.ruby }, 2)
dicdataStore.sendToDicdataStore(
.forgetMemory(
Candidate(
text: element.word,
value: element.value(),
correspondingCount: 3,
lastMid: element.mid,
data: [element]
)
)
)
let indices2 = dicdataStore.perfectMatchLOUDS(query: "memory", charIDs: charIDs)
let dicdata2 = dicdataStore.getDicdataFromLoudstxt3(identifier: "memory", indices: indices2)
XCTAssertFalse(dicdata2.contains { $0.word == element.word && $0.ruby == element.ruby })
}
}

View File

@ -34,6 +34,20 @@ final class TemporalLearningMemoryTrieTests: XCTestCase {
XCTAssertEqual(Set(prefixResult.map { $0.word }), Set([element1.word, element2.word]))
}
func testMemorizeTwice() throws {
var trie = TemporalLearningMemoryTrie()
let element1 = DicdataElement(word: "テスト", ruby: "テスト", cid: CIDData..cid, mid: MIDData..mid, value: -10)
trie.memorize(dicdataElement: element1, chars: chars(for: element1.ruby))
let element2 = DicdataElement(word: "テスト", ruby: "テスト", cid: CIDData..cid, mid: MIDData..mid, value: -10, adjust: 1.5)
trie.memorize(dicdataElement: element2, chars: chars(for: element2.ruby))
let result1 = trie.perfectMatch(chars: chars(for: element1.ruby))
XCTAssertEqual(result1.count, 1)
XCTAssertEqual(result1.first?.word, element1.word)
XCTAssertTrue(result1.first?.metadata.contains(.isLearned) ?? false)
}
func testMemorizeUpdateCountAndForget() throws {
var trie = TemporalLearningMemoryTrie()
let element = DicdataElement(word: "テスター", ruby: "テスター", cid: CIDData..cid, mid: MIDData..mid, value: -10)
@ -53,4 +67,21 @@ final class TemporalLearningMemoryTrieTests: XCTestCase {
XCTAssertTrue(trie.forget(dicdataElement: stored, chars: charIDs))
XCTAssertTrue(trie.perfectMatch(chars: charIDs).isEmpty)
}
func testCoarseForget() throws {
var trie = TemporalLearningMemoryTrie()
let element1 = DicdataElement(word: "テスター", ruby: "テスター", cid: CIDData..cid, mid: MIDData..mid, value: -10)
let element2 = DicdataElement(word: "テスター", ruby: "テスター", cid: CIDData..cid, mid: MIDData..mid, value: -10)
let charIDs = chars(for: "テスター")
trie.memorize(dicdataElement: element1, chars: charIDs)
trie.memorize(dicdataElement: element2, chars: charIDs)
// 2
XCTAssertEqual(trie.perfectMatch(chars: charIDs).count, 2)
// forget
XCTAssertTrue(trie.forget(dicdataElement: element1, chars: charIDs))
XCTAssertTrue(trie.perfectMatch(chars: charIDs).isEmpty)
}
}