From 61f5853ab9864ce60b2d93486642dd07a5602f1c Mon Sep 17 00:00:00 2001 From: Walter Oggioni Date: Sun, 26 Sep 2021 12:24:37 +0200 Subject: [PATCH] refactor --- benchmark/build.gradle | 19 +++ benchmark/build.gradle.kts | 28 ----- benchmark/settings.gradle.kts | 1 - .../woggioni}/klevtree/benchmark/Benchmark.kt | 7 +- build.gradle | 46 ++++++++ build.gradle.kts | 29 ----- gradle.properties | 12 +- settings.gradle | 16 +++ settings.gradle.kts | 2 - src/main/java9/module-info.java | 4 + .../kotlin/net/woggioni/klevtree/CharTrie.kt | 39 +++---- .../woggioni/klevtree/DistanceCalculator.kt | 65 +++++++++++ .../kotlin/net/woggioni/klevtree/LevTrie.kt | 108 +++--------------- src/main/kotlin/net/woggioni/klevtree/Trie.kt | 17 ++- .../kotlin/net/woggioni/klevtree/WordTrie.kt | 39 +++---- .../net/woggioni/klevtree/node/nodes.kt | 20 +--- .../net/woggioni/klevtree/LevtreeTest.kt | 51 ++++----- 17 files changed, 247 insertions(+), 256 deletions(-) create mode 100644 benchmark/build.gradle delete mode 100644 benchmark/build.gradle.kts delete mode 100644 benchmark/settings.gradle.kts rename benchmark/src/main/kotlin/{ => net/woggioni}/klevtree/benchmark/Benchmark.kt (89%) create mode 100644 build.gradle delete mode 100644 build.gradle.kts create mode 100644 settings.gradle delete mode 100644 settings.gradle.kts create mode 100644 src/main/java9/module-info.java create mode 100644 src/main/kotlin/net/woggioni/klevtree/DistanceCalculator.kt diff --git a/benchmark/build.gradle b/benchmark/build.gradle new file mode 100644 index 0000000..aa13589 --- /dev/null +++ b/benchmark/build.gradle @@ -0,0 +1,19 @@ +plugins { + id 'org.jetbrains.kotlin.jvm' + id 'application' +} + +dependencies { + implementation group: 'net.woggioni', name: 'jwo', version: getProperty('version.jwo') + implementation(rootProject) +// runtime(files(rootProject.projectDir.toPath().resolve("src/test/resources"))) +} + +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_11 +} + +application { + mainClassName = "net.woggioni.klevtree.benchmark.BenchmarkKt" +} diff --git a/benchmark/build.gradle.kts b/benchmark/build.gradle.kts deleted file mode 100644 index 9ce74f4..0000000 --- a/benchmark/build.gradle.kts +++ /dev/null @@ -1,28 +0,0 @@ -plugins { - kotlin("jvm") - application -} - -group = "woggioni.net" -version = "0.1" - -repositories { - mavenLocal() - mavenCentral() - jcenter() -} - -dependencies { - implementation(kotlin("stdlib-jdk8")) - compile(rootProject) -// runtime(files(rootProject.projectDir.toPath().resolve("src/test/resources"))) -} - -application { - mainClassName = "net.woggioni.klevtree.benchmark.BenchmarkKt" -} - -java { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 -} diff --git a/benchmark/settings.gradle.kts b/benchmark/settings.gradle.kts deleted file mode 100644 index beb5ede..0000000 --- a/benchmark/settings.gradle.kts +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = "klevtree-benchmark" diff --git a/benchmark/src/main/kotlin/klevtree/benchmark/Benchmark.kt b/benchmark/src/main/kotlin/net/woggioni/klevtree/benchmark/Benchmark.kt similarity index 89% rename from benchmark/src/main/kotlin/klevtree/benchmark/Benchmark.kt rename to benchmark/src/main/kotlin/net/woggioni/klevtree/benchmark/Benchmark.kt index ad80b4b..cac1df8 100644 --- a/benchmark/src/main/kotlin/klevtree/benchmark/Benchmark.kt +++ b/benchmark/src/main/kotlin/net/woggioni/klevtree/benchmark/Benchmark.kt @@ -1,14 +1,11 @@ package net.woggioni.klevtree.benchmark -import net.woggioni.klevtree.ILevTrie import net.woggioni.klevtree.LevTrie import java.io.BufferedReader import java.io.InputStreamReader import net.woggioni.jwo.Chronometer - - -fun main(args: Array) { +fun main() { val reader = BufferedReader( InputStreamReader(Chronometer::class.java.getResourceAsStream("/cracklib-small")) ) @@ -21,7 +18,7 @@ fun main(args: Array) { } finally { reader.close() } - tree.algorithm = ILevTrie.Algorithm.DAMERAU_LEVENSHTEIN + tree.algorithm = LevTrie.Algorithm.DAMERAU_LEVENSHTEIN tree.caseSensitive = false val chr = Chronometer() val keys = arrayOf("camel", "coriolis", "mattel", "cruzer", "cpoper", "roublesoot") diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..df43ae5 --- /dev/null +++ b/build.gradle @@ -0,0 +1,46 @@ +plugins { + id 'maven-publish' + id 'net.woggioni.gradle.multi-release-jar' + id 'org.jetbrains.kotlin.jvm' +} + + +allprojects { + group = "woggioni.net" + version = getProperty('version.klevtree') + + repositories { + maven { + url = woggioniMavenRepositoryUrl + } + mavenCentral() + } +} + +ext { + setProperty('jpms.module.name', 'net.woggioni.klevtree') +} + +dependencies { + implementation group: 'net.woggioni', name: 'jwo', version: getProperty('version.jwo') + + testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: getProperty('version.junitJupiter') + testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-params', version: getProperty('version.junitJupiter') + testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: getProperty('version.junitJupiter') + testRuntimeOnly group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: getProperty('version.log4j2') +} + +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_11 +} + +compileKotlin { + kotlinOptions.with { + jvmTarget = '1.8' + } +} + +test { + useJUnitPlatform() +} diff --git a/build.gradle.kts b/build.gradle.kts deleted file mode 100644 index 4cd4838..0000000 --- a/build.gradle.kts +++ /dev/null @@ -1,29 +0,0 @@ - -plugins { - kotlin("jvm") version "1.3.41" -} - -group = "woggioni.net" -version = "0.1" - -repositories { - mavenLocal() - mavenCentral() - jcenter() -} - -dependencies { - implementation(kotlin("stdlib-jdk8")) - compile("net.woggioni:jwo:1.0") - testImplementation ("junit:junit:4.12") - testImplementation("org.jetbrains.kotlin:kotlin-test-junit:1.3.41") - testImplementation("org.apache.logging.log4j:log4j-core:2.12.1") - testImplementation("org.apache.logging.log4j:log4j-slf4j-impl:2.12.1") -} - -java { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 -} - - diff --git a/gradle.properties b/gradle.properties index 29e08e8..7bdfea1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1,11 @@ -kotlin.code.style=official \ No newline at end of file +kotlin.code.style=official + +woggioniMavenRepositoryUrl=https://woggioni.net/mvn/ + +version.multiReleaseJarPlugin=0.1 +version.klevtree=1.0 +version.jwo=1.0 +version.junitJupiter=5.7.2 +version.slf4j=1.7.32 +version.kotlin=1.5.31 +version.log4j2=2.14.1 diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..8d2a5ad --- /dev/null +++ b/settings.gradle @@ -0,0 +1,16 @@ +pluginManagement { + repositories { + maven { + url = woggioniMavenRepositoryUrl + } + gradlePluginPortal() + } + + plugins { + id 'org.jetbrains.kotlin.jvm' version getProperty('version.kotlin') + id 'net.woggioni.gradle.multi-release-jar' version getProperty('version.multiReleaseJarPlugin') + } +} + +rootProject.name = 'klevtree' +include 'benchmark' \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts deleted file mode 100644 index 9f3f3ff..0000000 --- a/settings.gradle.kts +++ /dev/null @@ -1,2 +0,0 @@ -rootProject.name = "klevtree" -include("benchmark") \ No newline at end of file diff --git a/src/main/java9/module-info.java b/src/main/java9/module-info.java new file mode 100644 index 0000000..5adf97e --- /dev/null +++ b/src/main/java9/module-info.java @@ -0,0 +1,4 @@ +module net.woggioni.klevtree { + requires net.woggioni.jwo; + exports net.woggioni.klevtree; +} \ No newline at end of file diff --git a/src/main/kotlin/net/woggioni/klevtree/CharTrie.kt b/src/main/kotlin/net/woggioni/klevtree/CharTrie.kt index 71dde64..b7702b4 100644 --- a/src/main/kotlin/net/woggioni/klevtree/CharTrie.kt +++ b/src/main/kotlin/net/woggioni/klevtree/CharTrie.kt @@ -3,37 +3,32 @@ package net.woggioni.klevtree import net.woggioni.klevtree.node.CharNode import net.woggioni.klevtree.node.TrieNode -interface ICharTrie : Trie, Char, PAYLOAD> { - - class CaseInsensitiveKeyChecker : Trie.Keychecker { +open class CharTrie : Trie, Char, PAYLOAD>() { + private class CaseInsensitiveKeyChecker : Keychecker { override fun check(key1: Char?, key2: Char?) = key1 == key2 } - class CaseSensitiveKeyChecker : Trie.Keychecker { - override fun check(key1: Char?, key2: Char?) = key1?.toLowerCase() == key2?.toLowerCase() + private class CaseSensitiveKeyChecker : Keychecker { + override fun check(key1: Char?, key2: Char?) = key1?.lowercaseChar() == key2?.lowercaseChar() } - var caseSensitive : Boolean + override val root: TrieNode = CharNode(null) + override val tails = mutableListOf>() + override var keyChecker: Keychecker = CaseSensitiveKeyChecker() + + var caseSensitive : Boolean = true + set(value) { + if(value) { + keyChecker = CaseSensitiveKeyChecker() + } else { + keyChecker = CaseInsensitiveKeyChecker() + } + field = value + } fun add(word : String) = super.add(word.asIterable()) fun search(word : String) : TrieNode? = search(word.asIterable().toList()) fun remove(word : String) = remove(word.asIterable().toList()) -} - -class CharTrie : ICharTrie { - - override val root: TrieNode = CharNode(null) - override val tails = mutableListOf>() - override var keyChecker: Trie.Keychecker = ICharTrie.CaseSensitiveKeyChecker() - override var caseSensitive : Boolean = true - set(value) { - if(value) { - keyChecker = ICharTrie.CaseSensitiveKeyChecker() - } else { - keyChecker = ICharTrie.CaseInsensitiveKeyChecker() - } - field = value - } } \ No newline at end of file diff --git a/src/main/kotlin/net/woggioni/klevtree/DistanceCalculator.kt b/src/main/kotlin/net/woggioni/klevtree/DistanceCalculator.kt new file mode 100644 index 0000000..bd6d81e --- /dev/null +++ b/src/main/kotlin/net/woggioni/klevtree/DistanceCalculator.kt @@ -0,0 +1,65 @@ +package net.woggioni.klevtree + +import net.woggioni.jwo.TreeNodeVisitor + +sealed class DistanceCalculator { + abstract fun compute(keyChecker : Trie.Keychecker, + stack: List>, + wordkey: String, + worstCase : Int) : TreeNodeVisitor.VisitOutcome + + object LevenshteinDistanceCalculator : DistanceCalculator() { + override fun compute(keyChecker : Trie.Keychecker, + stack: List>, + wordkey: String, + worstCase: Int) : TreeNodeVisitor.VisitOutcome { + val previousStackElement = stack[stack.size - 2] + val currentStackElement = stack.last() + val previousRow : IntArray = previousStackElement.node.payload!! + val currentRow : IntArray = currentStackElement.node.payload!! + for (i in 1..wordkey.length) { + if(keyChecker.check(wordkey[i - 1], currentStackElement.node.key)) { + currentRow[i] = previousRow[i - 1] + } else { + currentRow[i] = Math.min(Math.min(currentRow[i - 1], previousRow[i -1]), previousRow[i]) + 1 + } + } + return if(worstCase >= 0 && worstCase <= currentRow.minOrNull()!!) { + TreeNodeVisitor.VisitOutcome.SKIP + } else { + TreeNodeVisitor.VisitOutcome.CONTINUE + } + } + } + + object DamerauLevenshteinDistanceCalculator : DistanceCalculator() { + override fun compute(keyChecker : Trie.Keychecker, + stack: List>, + wordkey: String, + worstCase : Int) : TreeNodeVisitor.VisitOutcome { + val pse = stack[stack.size - 2] + val cse = stack.last() + val prow : IntArray = pse.node.payload!! + val crow : IntArray = cse.node.payload!! + for (i in 1..wordkey.length) { + if (keyChecker.check(wordkey[i - 1], cse.node.key)) { + crow[i] = prow[i - 1] + } else { + crow[i] = Math.min(Math.min(crow[i - 1], prow[i - 1]), prow[i]) + 1 + } + if (stack.size > 2 && i > 1 && keyChecker.check(wordkey[i - 2], cse.node.key) + && keyChecker.check(wordkey[i - 1], pse.node.key)) { + val ppse = stack[stack.size - 3] + val pprow: IntArray = ppse.node.payload!! + crow[i] = Math.min(crow[i], pprow[i - 2] + 1) + } + } + return if(worstCase >= 0 && worstCase <= prow.minOrNull()!!) { + TreeNodeVisitor.VisitOutcome.SKIP + } else { + TreeNodeVisitor.VisitOutcome.CONTINUE + } + } + } +} + diff --git a/src/main/kotlin/net/woggioni/klevtree/LevTrie.kt b/src/main/kotlin/net/woggioni/klevtree/LevTrie.kt index b898b38..062896a 100644 --- a/src/main/kotlin/net/woggioni/klevtree/LevTrie.kt +++ b/src/main/kotlin/net/woggioni/klevtree/LevTrie.kt @@ -1,75 +1,17 @@ package net.woggioni.klevtree -import net.woggioni.jwo.tree.StackContext -import net.woggioni.jwo.tree.TreeNodeVisitor -import net.woggioni.jwo.tree.TreeWalker +import net.woggioni.jwo.TreeNodeVisitor +import net.woggioni.jwo.TreeWalker import net.woggioni.klevtree.node.CharNode import net.woggioni.klevtree.node.TrieNode -typealias LevNode = TrieNode +internal typealias LevNode = TrieNode -interface ILevTrie : ICharTrie { +class LevTrie : CharTrie() { - interface DistanceCalculator { - fun compute(keyChecker : Trie.Keychecker, - stack: List>, - wordkey: String, - worstCase : Int) : TreeNodeVisitor.VisitOutcome - } + override val root: TrieNode = CharNode(null) - object LevenshteinDistanceCalculator : DistanceCalculator { - override fun compute(keyChecker : Trie.Keychecker, - stack: List>, - wordkey: String, - worstCase: Int) : TreeNodeVisitor.VisitOutcome { - val previousStackElement = stack[stack.size - 2] - val currentStackElement = stack.last() - val previousRow : IntArray = previousStackElement.node.payload!! - val currentRow : IntArray = currentStackElement.node.payload!! - for (i in 1..wordkey.length) { - if(keyChecker.check(wordkey[i - 1], currentStackElement.node.key)) { - currentRow[i] = previousRow[i - 1] - } else { - currentRow[i] = Math.min(Math.min(currentRow[i - 1], previousRow[i -1]), previousRow[i]) + 1 - } - } - return if(worstCase >= 0 && worstCase <= currentRow.min()!!) { - TreeNodeVisitor.VisitOutcome.SKIP - } else { - TreeNodeVisitor.VisitOutcome.CONTINUE - } - } - } - - object DamerauLevenshteinDistanceCalculator : DistanceCalculator { - override fun compute(keyChecker : Trie.Keychecker, - stack: List>, - wordkey: String, - worstCase : Int) : TreeNodeVisitor.VisitOutcome { - val pse = stack[stack.size - 2] - val cse = stack.last() - val prow : IntArray = pse.node.payload!! - val crow : IntArray = cse.node.payload!! - for (i in 1..wordkey.length) { - if (keyChecker.check(wordkey[i - 1], cse.node.key)) { - crow[i] = prow[i - 1] - } else { - crow[i] = Math.min(Math.min(crow[i - 1], prow[i - 1]), prow[i]) + 1 - } - if (stack.size > 2 && i > 1 && keyChecker.check(wordkey[i - 2], cse.node.key) - && keyChecker.check(wordkey[i - 1], pse.node.key)) { - val ppse = stack[stack.size - 3] - val pprow: IntArray = ppse.node.payload!! - crow[i] = Math.min(crow[i], pprow[i - 2] + 1) - } - } - return if(worstCase >= 0 && worstCase <= prow.min()!!) { - TreeNodeVisitor.VisitOutcome.SKIP - } else { - TreeNodeVisitor.VisitOutcome.CONTINUE - } - } - } + override val tails = mutableListOf>() enum class Algorithm { /** @@ -82,20 +24,19 @@ interface ILevTrie : ICharTrie { DAMERAU_LEVENSHTEIN } - var distanceCalculator : DistanceCalculator + private var distanceCalculator : DistanceCalculator = DistanceCalculator.LevenshteinDistanceCalculator var algorithm : Algorithm get() { return when(distanceCalculator) { - LevenshteinDistanceCalculator -> Algorithm.LEVENSHTEIN - DamerauLevenshteinDistanceCalculator -> Algorithm.DAMERAU_LEVENSHTEIN - else -> Algorithm.LEVENSHTEIN + DistanceCalculator.LevenshteinDistanceCalculator -> Algorithm.LEVENSHTEIN + DistanceCalculator.DamerauLevenshteinDistanceCalculator -> Algorithm.DAMERAU_LEVENSHTEIN } } set(value) { - when(value) { - Algorithm.LEVENSHTEIN -> distanceCalculator = LevenshteinDistanceCalculator - Algorithm.DAMERAU_LEVENSHTEIN -> distanceCalculator = DamerauLevenshteinDistanceCalculator + distanceCalculator = when(value) { + Algorithm.LEVENSHTEIN -> DistanceCalculator.LevenshteinDistanceCalculator + Algorithm.DAMERAU_LEVENSHTEIN -> DistanceCalculator.DamerauLevenshteinDistanceCalculator } } @@ -103,7 +44,7 @@ interface ILevTrie : ICharTrie { val result = sortedSetOf>(compareBy({ it.second }, { it.first })) val requiredSize = word.length + 1 val visitor = object: TreeNodeVisitor { - override fun visitPre(stack: List>): TreeNodeVisitor.VisitOutcome { + override fun visitPre(stack: List>): TreeNodeVisitor.VisitOutcome { val currentStackElement = stack.last() val currentNode = currentStackElement.node if(currentNode.payload == null || @@ -136,29 +77,8 @@ interface ILevTrie : ICharTrie { } } } - val walker = TreeWalker(visitor) + val walker = TreeWalker(visitor) walker.walk(root) return result.toList() } -} - -class LevTrie : ILevTrie { - - override val root: TrieNode = CharNode(null) - - override val tails = mutableListOf>() - - override var keyChecker: Trie.Keychecker = ICharTrie.CaseSensitiveKeyChecker() - - override var caseSensitive : Boolean = true - set(value) { - if(value) { - keyChecker = ICharTrie.CaseSensitiveKeyChecker() - } else { - keyChecker = ICharTrie.CaseInsensitiveKeyChecker() - } - field = value - } - - override var distanceCalculator : ILevTrie.DistanceCalculator = ILevTrie.LevenshteinDistanceCalculator } \ No newline at end of file diff --git a/src/main/kotlin/net/woggioni/klevtree/Trie.kt b/src/main/kotlin/net/woggioni/klevtree/Trie.kt index 6c154dd..289466f 100644 --- a/src/main/kotlin/net/woggioni/klevtree/Trie.kt +++ b/src/main/kotlin/net/woggioni/klevtree/Trie.kt @@ -1,21 +1,20 @@ package net.woggioni.klevtree -import net.woggioni.jwo.tree.StackContext -import net.woggioni.jwo.tree.TreeNodeVisitor -import net.woggioni.jwo.tree.TreeWalker +import net.woggioni.jwo.TreeNodeVisitor +import net.woggioni.jwo.TreeWalker import net.woggioni.klevtree.node.TrieNode -interface Trie, KEY, PAYLOAD> { +abstract class Trie, KEY, PAYLOAD> { interface Keychecker { fun check(key1 : KEY?, key2 : KEY?) : Boolean } - var keyChecker : Keychecker + protected abstract var keyChecker : Keychecker - val root : TrieNode + protected abstract val root : TrieNode - val tails : MutableList> + protected abstract val tails : MutableList> val words : Iterable> get() { val res = object : Iterator> { @@ -126,7 +125,7 @@ interface Trie, KEY, PAYLOAD> { fun search(path : List) : TrieNode? { var result : TrieNode? = null val visitor = object: TreeNodeVisitor, Unit> { - override fun visitPre(stack: List, Unit>>): TreeNodeVisitor.VisitOutcome { + override fun visitPre(stack: List, Unit>>): TreeNodeVisitor.VisitOutcome { return if(stack.size == 1) { TreeNodeVisitor.VisitOutcome.CONTINUE } else { @@ -147,7 +146,7 @@ interface Trie, KEY, PAYLOAD> { } } } - val walker = TreeWalker, Unit>(visitor) + val walker = TreeWalker(visitor) walker.walk(root) return result } diff --git a/src/main/kotlin/net/woggioni/klevtree/WordTrie.kt b/src/main/kotlin/net/woggioni/klevtree/WordTrie.kt index eee9afb..bda6e5d 100644 --- a/src/main/kotlin/net/woggioni/klevtree/WordTrie.kt +++ b/src/main/kotlin/net/woggioni/klevtree/WordTrie.kt @@ -3,38 +3,33 @@ package net.woggioni.klevtree import net.woggioni.klevtree.node.StringNode import net.woggioni.klevtree.node.TrieNode -interface IWordTrie : Trie, String, PAYLOAD> { +open class WordTrie : Trie, String, PAYLOAD>() { - class CaseInsensitiveKeyChecker : Trie.Keychecker { + override val root: TrieNode = StringNode(null) + override val tails = mutableListOf>() + override var keyChecker: Keychecker = CaseSensitiveKeyChecker() + + private class CaseInsensitiveKeyChecker : Keychecker { override fun check(key1: String?, key2: String?) = key1 == key2 } - class CaseSensitiveKeyChecker : Trie.Keychecker { - override fun check(key1: String?, key2: String?) = key1?.toLowerCase() == key2?.toLowerCase() + private class CaseSensitiveKeyChecker : Keychecker { + override fun check(key1: String?, key2: String?) = key1?.lowercase() == key2?.lowercase() } - var caseSensitive : Boolean + var caseSensitive : Boolean = true + set(value) { + if(value) { + keyChecker = CaseSensitiveKeyChecker() + } else { + keyChecker = CaseInsensitiveKeyChecker() + } + field = value + } fun add(word : String, delimiter : String) = super.add(word.split(delimiter)) fun search(word : String, delimiter : String) : TrieNode? { return search(word.split(delimiter)) } -} - -class WordTrie : IWordTrie { - - override val root: TrieNode = StringNode(null) - override val tails = mutableListOf>() - override var keyChecker: Trie.Keychecker = IWordTrie.CaseSensitiveKeyChecker() - - override var caseSensitive : Boolean = true - set(value) { - if(value) { - keyChecker = IWordTrie.CaseSensitiveKeyChecker() - } else { - keyChecker = IWordTrie.CaseInsensitiveKeyChecker() - } - field = value - } } \ No newline at end of file diff --git a/src/main/kotlin/net/woggioni/klevtree/node/nodes.kt b/src/main/kotlin/net/woggioni/klevtree/node/nodes.kt index 32144df..7d4b863 100644 --- a/src/main/kotlin/net/woggioni/klevtree/node/nodes.kt +++ b/src/main/kotlin/net/woggioni/klevtree/node/nodes.kt @@ -1,8 +1,9 @@ package net.woggioni.klevtree.node -import net.woggioni.jwo.tree.TreeNode +import net.woggioni.jwo.TreeNodeVisitor -open class TrieNode(val key : T?) : TreeNode> { + +open class TrieNode(val key : T?) : TreeNodeVisitor.TreeNode> { var parent : TrieNode? = null var child : TrieNode? = null var next : TrieNode? = null @@ -36,21 +37,6 @@ open class TrieNode(val key : T?) : TreeNode> { } return chars.asReversed() } - -// fun root(node: TrieNode) : String { -// var node : TrieNode? = node -// val chars = mutableListOf() -// while(node != null) { -// val key = node.key -// if(key != Character.MIN_VALUE) { -// chars.add(node.key) -// } -// node = node.parent -// } -// val sb = StringBuilder() -// for(c in chars.asReversed()) sb.append(c) -// return sb.toString() -// } } class CharNode(key : Char?) : TrieNode(key) diff --git a/src/test/kotlin/net/woggioni/klevtree/LevtreeTest.kt b/src/test/kotlin/net/woggioni/klevtree/LevtreeTest.kt index a30ee2f..6b2f0cd 100644 --- a/src/test/kotlin/net/woggioni/klevtree/LevtreeTest.kt +++ b/src/test/kotlin/net/woggioni/klevtree/LevtreeTest.kt @@ -1,8 +1,7 @@ package net.woggioni.klevtree -import org.junit.Assert -import org.junit.Test - +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test class LevtreeTest { @@ -10,27 +9,27 @@ class LevtreeTest { fun trivialTest() { val tree = LevTrie() tree.caseSensitive = false - tree.algorithm = ILevTrie.Algorithm.DAMERAU_LEVENSHTEIN + tree.algorithm = LevTrie.Algorithm.DAMERAU_LEVENSHTEIN val word = "dailies" run { val pair = tree.add(word) - Assert.assertTrue(pair.first) + Assertions.assertTrue(pair.first) val node = tree.search(word) - Assert.assertNotNull(node) - Assert.assertEquals( + Assertions.assertNotNull(node) + Assertions.assertEquals( word, node!!.linealDescendant().fold(StringBuilder(), StringBuilder::append).toString() ) val result = tree.fuzzySearch(word, 5) - Assert.assertEquals(1, result.size) - Assert.assertEquals(word to 0, result[0]) + Assertions.assertEquals(1, result.size) + Assertions.assertEquals(word to 0, result[0]) } run { tree.remove(word) val node = tree.search(word) - Assert.assertNull(node) + Assertions.assertNull(node) val result = tree.fuzzySearch(word, 5) - Assert.assertEquals(0, result.size) + Assertions.assertEquals(0, result.size) } } @@ -60,25 +59,25 @@ class LevtreeTest { fun levenshteinDistanceTest() { val tree = initLevTrie() tree.caseSensitive = false - tree.algorithm = ILevTrie.Algorithm.LEVENSHTEIN + tree.algorithm = LevTrie.Algorithm.LEVENSHTEIN run { val word = "fired" val result = tree.fuzzySearch(word, 4) - Assert.assertEquals(4, result.size) - Assert.assertEquals("tired" to 1, result[0]) + Assertions.assertEquals(4, result.size) + Assertions.assertEquals("tired" to 1, result[0]) } run { val word = "tierd" val result = tree.fuzzySearch(word, 4) - Assert.assertEquals(4, result.size) - Assert.assertEquals("tired" to 2, result[0]) + Assertions.assertEquals(4, result.size) + Assertions.assertEquals("tired" to 2, result[0]) } run { val word = "tierd" tree.remove("tired") val result = tree.fuzzySearch(word, 4) - Assert.assertEquals(4, result.size) - Assert.assertEquals("trail" to 4, result[0]) + Assertions.assertEquals(4, result.size) + Assertions.assertEquals("trail" to 4, result[0]) } } @@ -86,26 +85,26 @@ class LevtreeTest { fun damerauLevenshteinDistanceTest() { val tree = initLevTrie() tree.caseSensitive = false - tree.algorithm = ILevTrie.Algorithm.DAMERAU_LEVENSHTEIN + tree.algorithm = LevTrie.Algorithm.DAMERAU_LEVENSHTEIN run { val word = "fired" val result = tree.fuzzySearch(word, 4) - Assert.assertEquals(4, result.size) - Assert.assertEquals("tired" to 1, result[0]) + Assertions.assertEquals(4, result.size) + Assertions.assertEquals("tired" to 1, result[0]) } run { val word = "capitvate" val result = tree.fuzzySearch(word, 4) - Assert.assertEquals(4, result.size) - Assert.assertEquals("captivate" to 1, result[0]) - Assert.assertEquals("captivity" to 3, result[1]) + Assertions.assertEquals(4, result.size) + Assertions.assertEquals("captivate" to 1, result[0]) + Assertions.assertEquals("captivity" to 3, result[1]) } run { tree.remove("captivate") val word = "capitvate" val result = tree.fuzzySearch(word, 4) - Assert.assertEquals(4, result.size) - Assert.assertEquals("captivity" to 3, result[0]) + Assertions.assertEquals(4, result.size) + Assertions.assertEquals("captivity" to 3, result[0]) } } } \ No newline at end of file