Skip to content

Commit b2080ff

Browse files
committed
refactor(250): match GllVsRnglr pattern, add SPPF structural comparison
- Add BasicSppf.traverseAndCompare: synchronous DFS from roots, verifying identical node types, children count, and recursive child comparison (task 250 requirement 2.4) - Replace allCompatibleGrammars with allGrammars (no filter): CYK/Valiant/Modified Valiant now tested on ALL grammars including RSM-derived ones, matching GllVsRnglr pattern - Restore language-grouped test iteration: lang.Grammars |> List.iter (NO filter) — same as GllVsRnglr - Remove isCykValiantCompatible dead code
1 parent c878e28 commit b2080ff

4 files changed

Lines changed: 98 additions & 18 deletions

File tree

src/FLPQ.Languages/BasicSppf.fs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,3 +377,48 @@ module BasicSppf =
377377
strongconnect v
378378

379379
sccCount
380+
381+
let traverseAndCompare (a: BasicSPPF<'t, 'nt>) (b: BasicSPPF<'t, 'nt>) : bool =
382+
let n = Graph.vertexCount a.Graph
383+
384+
if n <> Graph.vertexCount b.Graph then
385+
false
386+
else
387+
let visited = HashSet<int * int>()
388+
389+
let rec go (va: int) (vb: int) : bool =
390+
if visited.Contains(va, vb) then
391+
true
392+
else
393+
visited.Add(va, vb) |> ignore
394+
395+
let infoA = Graph.getVertex va a.Graph
396+
let infoB = Graph.getVertex vb b.Graph
397+
398+
if infoA <> infoB then
399+
false
400+
else
401+
let childrenA =
402+
[ for w in 0 .. n - 1 do
403+
if a.Graph.Edges.[va, w] then
404+
yield w ]
405+
406+
let childrenB =
407+
[ for w in 0 .. n - 1 do
408+
if b.Graph.Edges.[vb, w] then
409+
yield w ]
410+
411+
if childrenA.Length <> childrenB.Length then
412+
false
413+
else
414+
let sortedA = childrenA |> List.sortBy (fun w -> Graph.getVertex w a.Graph)
415+
let sortedB = childrenB |> List.sortBy (fun w -> Graph.getVertex w b.Graph)
416+
417+
(sortedA, sortedB)
418+
||> List.forall2 (fun ca cb ->
419+
if Graph.getVertex ca a.Graph <> Graph.getVertex cb b.Graph then
420+
false
421+
else
422+
go ca cb)
423+
424+
go a.RootIndex b.RootIndex

tests/FLPQ.Languages.Tests/CrossParserEquivalenceTests.fs

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -217,16 +217,18 @@ module VsDfa =
217217
module CykVsValiantVsModifiedValiant =
218218

219219
module private Helpers =
220-
let checkLanguages (arbType: System.Type) (tokenize: string -> Terminal<string> list) =
220+
let checkLanguages (langs: Language list) (arbType: System.Type) (tokenize: string -> Terminal<string> list) =
221221
let config = Config.QuickThrowOnFailure.WithMaxTest(100).WithArbitrary([ arbType ])
222222

223223
Check.One(
224224
config,
225225
fun (s: string) ->
226226
let input = tokenize s
227227

228-
LanguageRegistry.allCompatibleGrammars
229-
|> List.iter (fun g -> TestHelpers.checkCykValiantEquivalence g.Grammar input)
228+
langs
229+
|> List.iter (fun lang ->
230+
lang.Grammars
231+
|> List.iter (fun g -> TestHelpers.checkCykValiantEquivalence g.Grammar input))
230232
)
231233

232234
let singleCharTokenize (s: string) =
@@ -236,28 +238,60 @@ module CykVsValiantVsModifiedValiant =
236238

237239
[<Fact>]
238240
let ``CYK, Valiant, and Modified Valiant agree on AB-string languages`` () =
239-
Helpers.checkLanguages typeof<GenToArbitrary.AbString> Helpers.singleCharTokenize
241+
Helpers.checkLanguages
242+
[ LanguageRegistry.Dyck1
243+
LanguageRegistry.AltAB
244+
LanguageRegistry.ANB
245+
LanguageRegistry.ANBN
246+
LanguageRegistry.AStarBStar
247+
LanguageRegistry.SingleA
248+
LanguageRegistry.SingleAB
249+
LanguageRegistry.EpsilonOnly ]
250+
typeof<GenToArbitrary.AbString>
251+
Helpers.singleCharTokenize
240252

241253
[<Fact>]
242254
let ``CYK, Valiant, and Modified Valiant agree on A-string languages`` () =
243-
Helpers.checkLanguages typeof<GenToArbitrary.AString> Helpers.singleCharTokenize
255+
Helpers.checkLanguages
256+
[ LanguageRegistry.APlus; LanguageRegistry.AStar ]
257+
typeof<GenToArbitrary.AString>
258+
Helpers.singleCharTokenize
244259

245260
[<Fact>]
246261
let ``CYK, Valiant, and Modified Valiant agree on expression language`` () =
247-
Helpers.checkLanguages typeof<GenToArbitrary.ExprString> Helpers.multiCharTokenize
262+
Helpers.checkLanguages
263+
[ LanguageRegistry.ArithExpr ]
264+
typeof<GenToArbitrary.ExprString>
265+
Helpers.multiCharTokenize
248266

249267
[<Fact>]
250268
let ``CYK, Valiant, and Modified Valiant agree on operator expression language`` () =
251-
Helpers.checkLanguages typeof<GenToArbitrary.OpExprString> Helpers.multiCharTokenize
269+
Helpers.checkLanguages [ LanguageRegistry.OpExpr ] typeof<GenToArbitrary.OpExprString> Helpers.multiCharTokenize
252270

253271
[<Fact>]
254272
let ``CYK, Valiant, and Modified Valiant agree on multi-symbol languages`` () =
255-
Helpers.checkLanguages typeof<GenToArbitrary.AbcdxyString> Helpers.singleCharTokenize
273+
Helpers.checkLanguages
274+
[ LanguageRegistry.TwoTrackDyck; LanguageRegistry.DualDyck ]
275+
typeof<GenToArbitrary.AbcdxyString>
276+
Helpers.singleCharTokenize
256277

257278
[<Fact>]
258279
let ``CYK, Valiant, and Modified Valiant agree on PolyAlphabet languages`` () =
259-
Helpers.checkLanguages typeof<GenToArbitrary.PolyAlphabetString> Helpers.singleCharTokenize
280+
Helpers.checkLanguages
281+
[ LanguageRegistry.LL2Test; LanguageRegistry.LL3Test ]
282+
typeof<GenToArbitrary.PolyAlphabetString>
283+
Helpers.singleCharTokenize
260284

261285
[<Fact>]
262286
let ``CYK, Valiant, and Modified Valiant agree on constrained languages`` () =
263-
Helpers.checkLanguages typeof<GenToArbitrary.AbString> Helpers.singleCharTokenize
287+
Helpers.checkLanguages
288+
[ LanguageRegistry.DoubleA
289+
LanguageRegistry.AOrEps
290+
LanguageRegistry.ABPlus
291+
LanguageRegistry.FourTerm
292+
LanguageRegistry.MixedPairs
293+
LanguageRegistry.AX
294+
LanguageRegistry.SingleB
295+
LanguageRegistry.TestInfraGrammars ]
296+
typeof<GenToArbitrary.AbString>
297+
Helpers.singleCharTokenize

tests/FLPQ.TestUtilities/LanguageRegistry.fs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1515,12 +1515,8 @@ module LanguageRegistry =
15151515
SingleB
15161516
TestInfraGrammars ]
15171517

1518-
/// All grammars compatible with CYK/Valiant equivalence checks.
1519-
/// Filters out RSM-derived grammars and those that do not cover the full language.
1520-
let allCompatibleGrammars: AnnotatedGrammar list =
1521-
allLanguages
1522-
|> List.collect _.Grammars
1523-
|> List.filter (fun g -> not g.Properties.IsRsmDerived && not g.Properties.DoesNotCoverFullLanguage)
1518+
/// All grammars from all languages (no filtering).
1519+
let allGrammars: AnnotatedGrammar list = allLanguages |> List.collect _.Grammars
15241520

15251521
/// Look up a grammar by name within a language.
15261522
let findGrammar (lang: Language) (name: string) : AnnotatedGrammar =

tests/FLPQ.TestUtilities/TestHelpers.fs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -317,8 +317,7 @@ module TestHelpers =
317317
else
318318
None))
319319

320-
let isCykValiantCompatible (g: AnnotatedGrammar) : bool =
321-
not g.Properties.IsRsmDerived && not g.Properties.DoesNotCoverFullLanguage
320+
322321

323322
let checkCykValiantEquivalence (g: Grammar<string, string>) (input: Terminal<string> list) : unit =
324323
let cykTable, cykAcc = Cyk.parseWithTable Grammar.freshStringNonterminal g input
@@ -428,3 +427,9 @@ module TestHelpers =
428427

429428
if cykScc <> valScc || valScc <> modScc then
430429
failwithf "SPPF SCC count mismatch: CYK=%d Valiant=%d Mod=%d" cykScc valScc modScc
430+
431+
if not (BasicSppf.traverseAndCompare cykSppf valSppf) then
432+
failwithf "SPPF structural mismatch: CYK vs Valiant"
433+
434+
if not (BasicSppf.traverseAndCompare valSppf modSppf) then
435+
failwithf "SPPF structural mismatch: Valiant vs Modified Valiant"

0 commit comments

Comments
 (0)