diff --git a/src/commonMain/kotlin/ai/hypergraph/kaliningraph/automata/FSA.kt b/src/commonMain/kotlin/ai/hypergraph/kaliningraph/automata/FSA.kt index 5081f916..d2bdc412 100644 --- a/src/commonMain/kotlin/ai/hypergraph/kaliningraph/automata/FSA.kt +++ b/src/commonMain/kotlin/ai/hypergraph/kaliningraph/automata/FSA.kt @@ -116,27 +116,41 @@ open class FSA constructor(open val Q: TSA, open val init: Set<Σᐩ>, open val // } companion object { - fun levIntersect(str: Σᐩ, cfg: CFG, radius: Int): Boolean { + // Decides intersection non-emptiness for Levenshtein ball ∩ CFG + fun nonemptyLevInt(str: Σᐩ, cfg: CFG, radius: Int): Boolean { val levFSA = makeLevFSA(str, radius) val dp = Array(levFSA.numStates) { Array(levFSA.numStates) { BooleanArray(cfg.nonterminals.size) { false } } } levFSA.allIndexedTxs(cfg).forEach { (q0, nt, q1) -> dp[q0][q1][nt] = true } - println(dp.joinToString("\n") { it.joinToString(" ") { if (it.any { it }) "1" else "0" } }) - - for (p in 0 until levFSA.numStates) - for (q in (p + 1) until levFSA.numStates) - for ((w, /*->*/ x, z) in cfg.tripleIntProds) - if (!dp[p][q][w]) - for (r in levFSA.allPairs[p to q] ?: emptySet()) - if (dp[p][r][x] && dp[r][q][z]) { +// println("BEFORE (sum=${dp.sumOf { it.sumOf { it.sumOf { if(it) 1.0 else 0.0 } } }})") +// println(dp.joinToString("\n") { it.joinToString(" ") { if (it.any { it }) "1" else "0" } }) +// println(dp.joinToString("\n") { it.joinToString(" ") { it.joinToString("", "[", "]") { if (it) "1" else "0"} } }) + + val startIdx = cfg.bindex[START_SYMBOL] + var fresh = true + while (fresh) { + fresh = false + for (p in 0 until levFSA.numStates) + for (q in (p + 1) until levFSA.numStates) + for ((w, /*->*/ x, z) in cfg.tripleIntProds) + if (!dp[p][q][w]) + for (r in levFSA.allPairs[p to q] ?: emptySet()) + if (dp[p][r][x] && dp[r][q][z]) { // println("Found: ${levFSA.stateLst[p]} ${levFSA.stateLst[q]} / ${cfg.bindex[w]} -> ${cfg.bindex[x]} ${cfg.bindex[z]}") - dp[p][q][w] = true - break - } + if (p == 0 && w == startIdx && q in levFSA.finalIdxs) return true + dp[p][q][w] = true + fresh = true + break + } + } + +// println("AFTER (sum=${dp.sumOf { it.sumOf { it.sumOf { if(it) 1.0 else 0.0 } } }})") +// println(dp.joinToString("\n") { it.joinToString(" ") { if (it.any { it }) "1" else "0" } }) +// println(dp.joinToString("\n") { it.joinToString(" ") { it.joinToString("", "[", "]") { if (it) "1" else "0"} } }) - return levFSA.finalIdxs.any { f -> dp[0][f][cfg.bindex[START_SYMBOL]].also { if (it) println("Found: ${levFSA.stateLst[0]} ${levFSA.stateLst[f]}") } } + return false } } diff --git a/src/commonTest/kotlin/ai/hypergraph/kaliningraph/parsing/BarHillelTest.kt b/src/commonTest/kotlin/ai/hypergraph/kaliningraph/parsing/BarHillelTest.kt index 7e6998b4..8a41387a 100644 --- a/src/commonTest/kotlin/ai/hypergraph/kaliningraph/parsing/BarHillelTest.kt +++ b/src/commonTest/kotlin/ai/hypergraph/kaliningraph/parsing/BarHillelTest.kt @@ -467,21 +467,21 @@ class BarHillelTest { */ @Test fun matrixLBHTest() { - val str = "( ( (" + val str = "( ( ( ( (" println(str.tokenizeByWhitespace().size) val led = Grammars.dyck.LED(str) println("Language edit distance: $led") - measureTimedValue { FSA.levIntersect(str, Grammars.dyck, led) } + measureTimedValue { FSA.nonemptyLevInt(str, Grammars.dyck, led) } .also { println("${it.value} / ${it.duration}") } .also { assertTrue(it.value) } - measureTimedValue { FSA.levIntersect(str, Grammars.dyck, led + 1) } + measureTimedValue { FSA.nonemptyLevInt(str, Grammars.dyck, led + 1) } .also { println("${it.value} / ${it.duration}") } .also { assertTrue(it.value) } - measureTimedValue { FSA.levIntersect(str, Grammars.dyck, led - 1) } + measureTimedValue { FSA.nonemptyLevInt(str, Grammars.dyck, led - 1) } .also { println("${it.value} / ${it.duration}") } .also { assertFalse(it.value) } }