From 047d8af159446c671da13e8a2a28eff3624c30a5 Mon Sep 17 00:00:00 2001 From: breandan Date: Fri, 13 Oct 2023 10:22:54 -0400 Subject: [PATCH] speed up vestigial pruning --- .../kaliningraph/parsing/BarHillel.kt | 4 ++-- .../ai/hypergraph/kaliningraph/parsing/CFG.kt | 2 +- .../kaliningraph/parsing/Normalization.kt | 20 +++++++++++-------- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/commonMain/kotlin/ai/hypergraph/kaliningraph/parsing/BarHillel.kt b/src/commonMain/kotlin/ai/hypergraph/kaliningraph/parsing/BarHillel.kt index fcaee542..e67e1e1a 100644 --- a/src/commonMain/kotlin/ai/hypergraph/kaliningraph/parsing/BarHillel.kt +++ b/src/commonMain/kotlin/ai/hypergraph/kaliningraph/parsing/BarHillel.kt @@ -51,7 +51,7 @@ infix fun CFG.intersectLevFSA(fsa: FSA): CFG { return (initFinal + transits + binaryProds + unitProds).joinToString("\n") .parseCFG(normalize = false) .also { println("∩-grammar has ${it.size} total productions") } - .removeVestigalProductions().normalForm.noNonterminalStubs + .dropVestigialProductions().normalForm.noNonterminalStubs .also { println("∩-grammar has ${it.size} useful productions") } .also { println("∩-grammar construction took: ${clock.elapsedNow().inWholeMilliseconds}ms") } // .also { println(it.pretty) } @@ -89,7 +89,7 @@ infix fun CFG.intersect(fsa: FSA): CFG { return (initFinal + transits + binaryProds + unitProds).joinToString("\n") .parseCFG(normalize = false) .also { println("∩-grammar has ${it.size} total productions") } - .removeVestigalProductions().normalForm.noNonterminalStubs + .dropVestigialProductions().normalForm.noNonterminalStubs .also { println("∩-grammar has ${it.size} useful productions") } .also { println("∩-grammar construction took: ${clock.elapsedNow().inWholeMilliseconds}ms") } // .also { println(it.pretty) } diff --git a/src/commonMain/kotlin/ai/hypergraph/kaliningraph/parsing/CFG.kt b/src/commonMain/kotlin/ai/hypergraph/kaliningraph/parsing/CFG.kt index a78fad95..ae1d4e17 100644 --- a/src/commonMain/kotlin/ai/hypergraph/kaliningraph/parsing/CFG.kt +++ b/src/commonMain/kotlin/ai/hypergraph/kaliningraph/parsing/CFG.kt @@ -99,7 +99,7 @@ val CFG.noNonterminalStubs: CFG by cache { val CFG.noEpsilonOrNonterminalStubs: CFG by cache { println("Disabling nonterminal stubs!") filter { it.RHS.none { it.isNonterminalStubIn(this) } } - .filter { "ε" !in it.toString() }.toSet().removeVestigalProductions() + .filter { "ε" !in it.toString() }.toSet().dropVestigialProductions() .also { rewriteHistory.put(it, freeze().let { rewriteHistory[it]!! + listOf(it)}) } .also { it.blocked.addAll(blocked) } } diff --git a/src/commonMain/kotlin/ai/hypergraph/kaliningraph/parsing/Normalization.kt b/src/commonMain/kotlin/ai/hypergraph/kaliningraph/parsing/Normalization.kt index c27bbb69..c55a224e 100644 --- a/src/commonMain/kotlin/ai/hypergraph/kaliningraph/parsing/Normalization.kt +++ b/src/commonMain/kotlin/ai/hypergraph/kaliningraph/parsing/Normalization.kt @@ -14,16 +14,17 @@ val rewriteHistory = LRUCache>() // Recursively removes all productions from a synthetic CFG containing a // dangling nonterminal, i.e., a nonterminal that does not produce any terminals. -fun CFG.removeVestigalProductions( +fun CFG.dropVestigialProductions( criteria: (Σᐩ) -> Boolean = { it.first() == '[' && it.last() == ']' && it.count { it == ',' } == 2 } ): CFG { - val rw = - filter { it.RHS.all { !criteria(it) || it in nonterminals } } - .toSet().removeUselessSymbols() + val nts: Set<Σᐩ> = map { it.LHS }.toSet() + val rw = toMutableSet() + .apply { removeAll { !it.RHS.all { !criteria(it) || it in nts } } } + .removeUselessSymbols() // println("Removed ${size - rw.size} vestigal productions.") - return if (rw.size == size) this else rw.removeVestigalProductions(criteria) + return if (rw.size == size) this else rw.dropVestigialProductions(criteria) } /** @@ -47,7 +48,7 @@ fun CFG.normalize(): CFG = // ./gradlew jvmTest --tests "ai.hypergraph.kaliningraph.sat.SATValiantTest.testTLArithmetic" .generateNonterminalStubs() // Should only need to run this on synthetic CFGs - .removeVestigalProductions() + .dropVestigialProductions() .also { cnf -> rewriteHistory.put(cnf.freeze(), rewrites) } } @@ -180,7 +181,10 @@ fun CFG.refactorEpsilonProds(nlbls: Set<Σᐩ> = nullableNonterminals()): CFG = fun CFG.removeUselessSymbols( generating: Set<Σᐩ> = generatingSymbols(), reachable: Set<Σᐩ> = reachableSymbols() -): CFG = partition { (s, _) -> s in generating intersect reachable } +): CFG = + toMutableSet().apply { + removeAll { (s, _) -> !(s in generating && s in reachable) } + } // .also { // println( // it.second.joinToString("\n") { (l, r) -> @@ -191,7 +195,7 @@ fun CFG.removeUselessSymbols( // } // ) // } - .first.toSet() +// .first.toSet() fun CFG.equivalenceClass(from: Σᐩ): Set<Σᐩ> = unitReachability[from] ?: setOf(from)